diff --git a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake index 6192d809a3..1065ecd0e3 100644 --- a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake +++ b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake @@ -511,11 +511,13 @@ macro(qt_build_tests) if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/auto/CMakeLists.txt") add_subdirectory(auto) endif() - if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/benchmarks/CMakeLists.txt" AND QT_BUILD_BENCHMARKS) - add_subdirectory(benchmarks) - endif() - if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/manual/CMakeLists.txt" AND QT_BUILD_MANUAL_TESTS) - add_subdirectory(manual) + if(NOT QT_BUILD_MINIMAL_STATIC_TESTS) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/benchmarks/CMakeLists.txt" AND QT_BUILD_BENCHMARKS) + add_subdirectory(benchmarks) + endif() + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/manual/CMakeLists.txt" AND QT_BUILD_MANUAL_TESTS) + add_subdirectory(manual) + endif() endif() endmacro() diff --git a/cmake/QtProcessConfigureArgs.cmake b/cmake/QtProcessConfigureArgs.cmake index cab1db7f04..330de3e6b3 100644 --- a/cmake/QtProcessConfigureArgs.cmake +++ b/cmake/QtProcessConfigureArgs.cmake @@ -662,7 +662,7 @@ function(check_qt_build_parts type) set(buildFlag "FALSE") endif() - list(APPEND knownParts "tests" "examples" "benchmarks") + list(APPEND knownParts "tests" "examples" "benchmarks" "manual-tests" "minimal-static-tests") foreach(part ${${input}}) if(part IN_LIST knownParts) diff --git a/cmake/QtSetup.cmake b/cmake/QtSetup.cmake index bd81da9eb1..83e932da55 100644 --- a/cmake/QtSetup.cmake +++ b/cmake/QtSetup.cmake @@ -164,6 +164,7 @@ option(QT_BUILD_EXAMPLES "Build Qt examples" OFF) option(QT_BUILD_EXAMPLES_BY_DEFAULT "Should examples be built as part of the default 'all' target." ON) option(QT_BUILD_MANUAL_TESTS "Build Qt manual tests" OFF) +option(QT_BUILD_MINIMAL_STATIC_TESTS "Build minimal subset of tests for static Qt builds" OFF) ## Find host tools (if non native): set(QT_HOST_PATH "" CACHE PATH "Installed Qt host directory path, used for cross compiling.") diff --git a/coin/instructions/cmake_build_and_upload_test_artifacts.yaml b/coin/instructions/cmake_build_and_upload_test_artifacts.yaml index 84077980b8..4b3e3d46bf 100644 --- a/coin/instructions/cmake_build_and_upload_test_artifacts.yaml +++ b/coin/instructions/cmake_build_and_upload_test_artifacts.yaml @@ -23,6 +23,15 @@ instructions: env_var: COIN_CMAKE_ARGS equals_value: null + # Inform CMake to build just a minimal set of tests for static Qt builds. + - type: AppendToEnvironmentVariable + variableName: COIN_CMAKE_ARGS + variableValue: " -DQT_BUILD_MINIMAL_STATIC_TESTS=ON" + enable_if: + condition: property + property: features + contains_value: "MinimalStaticTests" + - !include "{{qt/qtbase}}/call_cmake_for_standalone_tests.yaml" - type: ExecuteCommand command: "{{.Env.TESTS_ENV_PREFIX}} cmake --build . --parallel -v" @@ -35,7 +44,3 @@ instructions: archiveDirectory: "{{.BuildDir}}" maxTimeInSeconds: 1200 maxTimeBetweenOutput: 1200 -disable_if: - condition: property - property: configureArgs - contains_value: "-DBUILD_SHARED_LIBS=OFF" diff --git a/coin/instructions/cmake_regular_test_instructions_enforced.yaml b/coin/instructions/cmake_regular_test_instructions_enforced.yaml index b7308a8f47..197b925c2a 100644 --- a/coin/instructions/cmake_regular_test_instructions_enforced.yaml +++ b/coin/instructions/cmake_regular_test_instructions_enforced.yaml @@ -2,7 +2,3 @@ type: Group instructions: - !include "{{qt/qtbase}}/cmake_regular_test_instructions_common.yaml" - !include "{{qt/qtbase}}/cmake_run_ctest_enforce_exit_code.yaml" -disable_if: - condition: property - property: configureArgs - contains_value: "-DBUILD_SHARED_LIBS=OFF" diff --git a/config_help.txt b/config_help.txt index b2de3dd33c..f010cccf1a 100644 --- a/config_help.txt +++ b/config_help.txt @@ -175,8 +175,10 @@ Component selection: -skip ......... Exclude an entire repository from the build. -make ......... Add to the list of parts to be built. Specifying this option clears the default list first. - [libs and examples, also tools if not cross-building, - also tests if -developer-build] + (allowed values: libs, tools, examples, tests, + benchmarks, manual-tests, minimal-static-tests) + [default: libs and examples, also tools if not + cross-building, also tests if -developer-build] -nomake ....... Exclude from the list of parts to be built. -gui ................. Build the Qt GUI module and dependencies [yes] -widgets ............. Build the Qt Widgets module and dependencies [yes] diff --git a/qt_cmdline.cmake b/qt_cmdline.cmake index a476d05c35..521d32d975 100644 --- a/qt_cmdline.cmake +++ b/qt_cmdline.cmake @@ -74,13 +74,14 @@ qt_commandline_option(linker TYPE optionalString VALUES bfd gold lld) qt_commandline_option(ltcg TYPE boolean) # special case begin qt_commandline_option(make TYPE addString VALUES examples libs tests tools - benchmarks) + benchmarks manual-tests minimal-static-tests) # special case end qt_commandline_option(make-tool TYPE string) qt_commandline_option(mips_dsp TYPE boolean) qt_commandline_option(mips_dspr2 TYPE boolean) qt_commandline_option(mp TYPE boolean NAME msvc_mp) -qt_commandline_option(nomake TYPE addString VALUES examples tests tools benchmarks) # special case +qt_commandline_option(nomake TYPE addString VALUES examples tests tools benchmarks + manual-tests minimal-static-tests) # special case qt_commandline_option(opensource TYPE void NAME commercial VALUE no) qt_commandline_option(optimize-debug TYPE boolean NAME optimize_debug) qt_commandline_option(optimize-size TYPE boolean NAME optimize_size) diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index 638405ae75..b8ab7c8ffd 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -408,6 +408,14 @@ bool QWindowsPipeReader::consumePendingAndEmit(bool allowWinActPosting) mutex.unlock(); + // Trigger 'pipeBroken' only once. This flag must be updated before + // emitting the readyRead() signal. Otherwise, the read sequence will + // be considered not finished, and we may hang if a slot connected + // to readyRead() calls waitForReadyRead(). + const bool emitPipeClosed = (dwError != ERROR_SUCCESS && !pipeBroken); + if (emitPipeClosed) + pipeBroken = true; + // Disable any further processing, if the pipe was stopped. // We are not allowed to emit signals in either 'Stopped' // or 'Draining' state. @@ -418,10 +426,7 @@ bool QWindowsPipeReader::consumePendingAndEmit(bool allowWinActPosting) QScopedValueRollback guard(inReadyRead, true); emit readyRead(); } - - // Trigger 'pipeBroken' only once. - if (dwError != ERROR_SUCCESS && !pipeBroken) { - pipeBroken = true; + if (emitPipeClosed) { if (dwError != ERROR_BROKEN_PIPE && dwError != ERROR_PIPE_NOT_CONNECTED) emit winError(dwError, QLatin1String("QWindowsPipeReader::consumePendingAndEmit")); emit pipeClosed(); diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt index 2452e1a5d8..c16c8b197b 100644 --- a/tests/auto/CMakeLists.txt +++ b/tests/auto/CMakeLists.txt @@ -22,6 +22,12 @@ if (TARGET Qt::Xml AND TARGET Qt::Sql AND TARGET Qt::Network) add_subdirectory(cmake) endif() # special case end + +# Limit set of tests to run for static Qt builds. +if(QT_BUILD_MINIMAL_STATIC_TESTS) + return() +endif() + if (TARGET Qt::Concurrent) add_subdirectory(concurrent) endif() diff --git a/tests/auto/cmake/test_interface/CMakeLists.txt b/tests/auto/cmake/test_interface/CMakeLists.txt index 0cae16668e..d874ac561d 100644 --- a/tests/auto/cmake/test_interface/CMakeLists.txt +++ b/tests/auto/cmake/test_interface/CMakeLists.txt @@ -14,23 +14,15 @@ add_executable(test_interface_exe WIN32 main.cpp mainwindow.cpp) # link explicitly to Qt::WinMain. target_link_libraries(test_interface_exe Qt::Widgets) -file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/try_compile-test.cpp" - " -#include -#include - -int main(int,char**) { QWidget w; w.show(); return 0; } -" -) - # Fix try_compile to inherit the parent configuration. set(CMAKE_TRY_COMPILE_CONFIGURATION "${CMAKE_BUILD_TYPE}") -# The try_compile works because Qt::Widgets is listed in the LINK_LIBRARIES, -# which causes the includes, defines and appropriate PIC flag to be used. -try_compile(_TRY_COMPILE_RES "${CMAKE_CURRENT_BINARY_DIR}/try_compile-test" - "${CMAKE_CURRENT_BINARY_DIR}/try_compile-test.cpp" - LINK_LIBRARIES Qt::Widgets +# Can't use source file based try_compile, because it doesn't handle object libraries +# referenced in generator expressions properly. +try_compile(_TRY_COMPILE_RES + "${CMAKE_CURRENT_BINARY_DIR}/widget_test" + "${CMAKE_CURRENT_SOURCE_DIR}/widget_test" + widget_test OUTPUT_VARIABLE TC_OV ) diff --git a/tests/auto/cmake/test_interface/widget_test/CMakeLists.txt b/tests/auto/cmake/test_interface/widget_test/CMakeLists.txt new file mode 100644 index 0000000000..679d01ef63 --- /dev/null +++ b/tests/auto/cmake/test_interface/widget_test/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.14) + +project(test_interface_try_compile) + +find_package(Qt6Widgets) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +add_executable(test_interface_try_compile_exe main.cpp) +target_link_libraries(test_interface_try_compile_exe Qt::Widgets) + diff --git a/tests/auto/cmake/test_interface/widget_test/main.cpp b/tests/auto/cmake/test_interface/widget_test/main.cpp new file mode 100644 index 0000000000..e6a8ab5fe9 --- /dev/null +++ b/tests/auto/cmake/test_interface/widget_test/main.cpp @@ -0,0 +1,4 @@ +#include +#include + +int main(int, char**) { QWidget w; w.show(); return 0; } diff --git a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp index 7667cb278e..b089381272 100644 --- a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp +++ b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp @@ -746,6 +746,9 @@ void tst_qmessagehandler::qMessagePattern_data() #define QT_NAMESPACE_STR "" #endif +#if QT_CONFIG(static) + QSKIP("These test cases don't work with static Qt builds"); +#else #ifndef QT_NO_DEBUG QTest::newRow("backtrace") << "[%{backtrace}] %{message}" << true << (QList() // MyClass::qt_static_metacall is explicitly marked as hidden in the Q_OBJECT macro @@ -755,7 +758,8 @@ void tst_qmessagehandler::qMessagePattern_data() QTest::newRow("backtrace depth,separator") << "[%{backtrace depth=2 separator=\"\n\"}] %{message}" << true << (QList() << "[MyClass::myFunction\nMyClass::mySlot1] from_a_function 34" << "[T::T\n"); -#endif +#endif // #if !QT_CONFIG(process) +#endif // #ifdef __GLIBC__ } diff --git a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp index f20f82ff88..eebbf4ef24 100644 --- a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp +++ b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp @@ -111,6 +111,7 @@ private slots: void longPath(); void waitForDisconnect(); void waitForDisconnectByServer(); + void waitForReadyReadOnDisconnected(); void removeServer(); @@ -1151,6 +1152,40 @@ void tst_QLocalSocket::waitForDisconnectByServer() QCOMPARE(spy.count(), 1); } +void tst_QLocalSocket::waitForReadyReadOnDisconnected() +{ + QString name = "tst_localsocket"; + LocalServer server; + QVERIFY(server.listen(name)); + LocalSocket socket; + connect(&socket, &QLocalSocket::readyRead, [&socket]() { + QVERIFY(socket.getChar(nullptr)); + // The next call should not block because the socket was closed + // by the peer. + QVERIFY(!socket.waitForReadyRead(3000)); + }); + + socket.connectToServer(name); + QVERIFY(socket.waitForConnected(3000)); + QVERIFY(server.waitForNewConnection(3000)); + QLocalSocket *serverSocket = server.nextPendingConnection(); + QVERIFY(serverSocket); + QVERIFY(serverSocket->putChar(0)); + QVERIFY(serverSocket->waitForBytesWritten(3000)); + serverSocket->close(); + +#ifdef Q_OS_WIN + // Ensure that the asynchronously delivered close notification is + // already queued up before we consume the data. + QTest::qSleep(250); +#endif + + QElapsedTimer timer; + timer.start(); + QVERIFY(socket.waitForReadyRead(5000)); + QVERIFY(timer.elapsed() < 2000); +} + void tst_QLocalSocket::removeServer() { // this is a hostile takeover, but recovering from a crash results in the same