diff options
Diffstat (limited to 'cmake/QtTestHelpers.cmake')
-rw-r--r-- | cmake/QtTestHelpers.cmake | 875 |
1 files changed, 653 insertions, 222 deletions
diff --git a/cmake/QtTestHelpers.cmake b/cmake/QtTestHelpers.cmake index 3add288b3d..705de2f739 100644 --- a/cmake/QtTestHelpers.cmake +++ b/cmake/QtTestHelpers.cmake @@ -1,14 +1,21 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + # Simple wrapper around qt_internal_add_executable for benchmarks which insure that # the binary is built under ${CMAKE_CURRENT_BINARY_DIR} and never installed. # See qt_internal_add_executable() for more details. function(qt_internal_add_benchmark target) + if(QT_BUILD_TESTS_BATCHED) + message(WARNING "Benchmarks won't be batched - unsupported (yet)") + endif() - qt_parse_all_arguments(arg "qt_add_benchmark" + cmake_parse_arguments(PARSE_ARGV 1 arg "${__qt_internal_add_executable_optional_args}" "${__qt_internal_add_executable_single_args}" "${__qt_internal_add_executable_multi_args}" - ${ARGN} ) + _qt_internal_validate_all_args_are_parsed(arg) + _qt_internal_validate_no_unity_build(arg) qt_remove_args(exec_args ARGS_TO_REMOVE @@ -24,20 +31,41 @@ function(qt_internal_add_benchmark target) ) if(NOT arg_OUTPUT_DIRECTORY) - set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + if(CMAKE_RUNTIME_OUTPUT_DIRECTORY) + set(arg_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") + else() + set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + endif() endif() + qt_internal_library_deprecation_level(deprecation_define) + qt_internal_add_executable(${target} NO_INSTALL # we don't install benchmarks + NO_UNITY_BUILD # excluded by default OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" # avoid polluting bin directory ${exec_args} ) + qt_internal_extend_target(${target} + DEFINES + ${deprecation_define} + ) + + # Benchmarks on iOS must be app bundles. + if(IOS) + set_target_properties(${target} PROPERTIES MACOSX_BUNDLE TRUE) + endif() + + qt_internal_add_repo_local_defines(${target}) + + # Disable the QT_NO_NARROWING_CONVERSIONS_IN_CONNECT define for benchmarks + qt_internal_undefine_global_definition(${target} QT_NO_NARROWING_CONVERSIONS_IN_CONNECT) qt_internal_collect_command_environment(benchmark_env_path benchmark_env_plugin_path) # Add a ${target}_benchmark generator target, to run single benchmark more easily. set(benchmark_wrapper_file "${arg_OUTPUT_DIRECTORY}/${target}Wrapper$<CONFIG>.cmake") - qt_internal_create_command_script(COMMAND "$<TARGET_FILE:${target}>" + _qt_internal_create_command_script(COMMAND "$<TARGET_FILE:${target}>" OUTPUT_FILE "${benchmark_wrapper_file}" ENVIRONMENT "PATH" "${benchmark_env_path}" "QT_PLUGIN_PATH" "${benchmark_env_plugin_path}" @@ -55,43 +83,22 @@ function(qt_internal_add_benchmark target) if (TARGET benchmark) add_dependencies("benchmark" "${target}_benchmark") endif() + + qt_internal_add_test_finalizers("${target}") +endfunction() + +function(qt_internal_add_test_dependencies target) + if(QT_BUILD_TESTS_BATCHED) + _qt_internal_test_batch_target_name(target) + endif() + add_dependencies(${target} ${ARGN}) endfunction() # Simple wrapper around qt_internal_add_executable for manual tests which insure that # the binary is built under ${CMAKE_CURRENT_BINARY_DIR} and never installed. # See qt_internal_add_executable() for more details. function(qt_internal_add_manual_test target) - - qt_parse_all_arguments(arg "qt_add_manual_test" - "${__qt_internal_add_executable_optional_args}" - "${__qt_internal_add_executable_single_args}" - "${__qt_internal_add_executable_multi_args}" - ${ARGN} - ) - - qt_remove_args(exec_args - ARGS_TO_REMOVE - ${target} - OUTPUT_DIRECTORY - INSTALL_DIRECTORY - ALL_ARGS - "${__qt_internal_add_executable_optional_args}" - "${__qt_internal_add_executable_single_args}" - "${__qt_internal_add_executable_multi_args}" - ARGS - ${ARGV} - ) - - if(NOT arg_OUTPUT_DIRECTORY) - set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") - endif() - - qt_internal_add_executable(${target} - NO_INSTALL # we don't install benchmarks - OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" # avoid polluting bin directory - ${exec_args} - ) - + qt_internal_add_test(${ARGV} MANUAL) endfunction() # This function will configure the fixture for the network tests that require docker network services @@ -102,6 +109,11 @@ function(qt_internal_setup_docker_test_fixture name) return() endif() + option(QT_SKIP_DOCKER_COMPOSE "Skip setting up docker on Linux." OFF) + if(QT_SKIP_DOCKER_COMPOSE) + return() + endif() + set(QT_TEST_SERVER_LIST ${ARGN}) set(DNSDOMAIN test-net.qt.local) @@ -140,6 +152,8 @@ function(qt_internal_setup_docker_test_fixture name) if(DEFINED QT_TESTSERVER_COMPOSE_FILE) set(TESTSERVER_COMPOSE_FILE ${QT_TESTSERVER_COMPOSE_FILE}) + elseif(QNX) + set(TESTSERVER_COMPOSE_FILE "${QT_SOURCE_TREE}/tests/testserver/docker-compose-qemu-bridge-network.yml") else() set(TESTSERVER_COMPOSE_FILE "${QT_SOURCE_TREE}/tests/testserver/docker-compose-bridge-network.yml") endif() @@ -166,6 +180,256 @@ function(qt_internal_setup_docker_test_fixture name) endfunction() +function(qt_internal_get_test_batch out) + get_property(batched_list GLOBAL PROPERTY _qt_batched_test_list_property) + set(${out} ${batched_list} PARENT_SCOPE) +endfunction() + +function(qt_internal_prepare_test_target_flags version_arg exceptions_text gui_text) + cmake_parse_arguments(arg "EXCEPTIONS;NO_EXCEPTIONS;GUI" "VERSION" "" ${ARGN}) + + if (arg_VERSION) + set(${version_arg} VERSION "${arg_VERSION}" PARENT_SCOPE) + endif() + + # Qt modules get compiled without exceptions enabled by default. + # However, testcases should be still built with exceptions. + set(${exceptions_text} "EXCEPTIONS" PARENT_SCOPE) + if (${arg_NO_EXCEPTIONS} OR WASM) + set(${exceptions_text} "" PARENT_SCOPE) + endif() + + if (${arg_GUI}) + set(${gui_text} "GUI" PARENT_SCOPE) + endif() +endfunction() + +function(qt_internal_get_test_arg_definitions optional_args single_value_args multi_value_args) + set(${optional_args} + RUN_SERIAL + EXCEPTIONS + NO_EXCEPTIONS + GUI + QMLTEST + CATCH + LOWDPI + NO_WRAPPER + BUILTIN_TESTDATA + MANUAL + NO_BATCH + NO_INSTALL + BUNDLE_ANDROID_OPENSSL_LIBS + PARENT_SCOPE + ) + set(${single_value_args} + OUTPUT_DIRECTORY + WORKING_DIRECTORY + TIMEOUT + VERSION + PARENT_SCOPE + ) + set(${multi_value_args} + QML_IMPORTPATH + TESTDATA + QT_TEST_SERVER_LIST + ${__default_private_args} + ${__default_public_args} + PARENT_SCOPE + ) +endfunction() + +function(qt_internal_add_test_to_batch batch_name name) + qt_internal_get_test_arg_definitions(optional_args single_value_args multi_value_args) + + cmake_parse_arguments( + arg "${optional_args}" "${single_value_args}" "${multi_value_args}" ${ARGN}) + qt_internal_prepare_test_target_flags(version_arg exceptions_text gui_text ${ARGN}) + + _qt_internal_validate_no_unity_build(arg) + + _qt_internal_test_batch_target_name(target) + + # Lazy-init the test batch + if(NOT TARGET ${target}) + qt_internal_library_deprecation_level(deprecation_define) + qt_internal_add_executable(${target} + ${exceptions_text} + ${gui_text} + ${version_arg} + NO_INSTALL + OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/build_dir" + SOURCES "${QT_CMAKE_DIR}/qbatchedtestrunner.in.cpp" + DEFINES QTEST_BATCH_TESTS ${deprecation_define} + INCLUDE_DIRECTORIES ${private_includes} + LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Core + ${QT_CMAKE_EXPORT_NAMESPACE}::Test + ${QT_CMAKE_EXPORT_NAMESPACE}::TestPrivate + # Add GUI by default so that the plugins link properly with non-standalone + # build of tests. Plugin handling is currently only done in + # qt_internal_add_executable if Gui is present. This should be reevaluated with + # multiple batches. + ${QT_CMAKE_EXPORT_NAMESPACE}::Gui + ) + + set_property(TARGET ${target} PROPERTY _qt_has_exceptions ${arg_EXCEPTIONS}) + set_property(TARGET ${target} PROPERTY _qt_has_gui ${arg_GUI}) + set_property(TARGET ${target} PROPERTY _qt_has_lowdpi ${arg_LOWDPI}) + set_property(TARGET ${target} PROPERTY _qt_version ${version_arg}) + set_property(TARGET ${target} PROPERTY _qt_is_test_executable TRUE) + set_property(TARGET ${target} PROPERTY _qt_is_manual_test ${arg_MANUAL}) + else() + # Check whether the args match with the batch. Some differences between + # flags cannot be reconciled - one should not combine these tests into + # a single binary. + qt_internal_get_target_property( + batch_has_exceptions ${target} _qt_has_exceptions) + if(NOT ${batch_has_exceptions} STREQUAL ${arg_EXCEPTIONS}) + qt_internal_get_test_batch(test_batch_contents) + message(FATAL_ERROR "Conflicting exceptions declaration between test \ + batch (${test_batch_contents}) and ${name}") + endif() + qt_internal_get_target_property(batch_has_gui ${target} _qt_has_gui) + if(NOT ${batch_has_gui} STREQUAL ${arg_GUI}) + qt_internal_get_test_batch(test_batch_contents) + message(FATAL_ERROR "Conflicting gui declaration between test batch \ + (${test_batch_contents}) and ${name}") + endif() + qt_internal_get_target_property( + batch_has_lowdpi ${target} _qt_has_lowdpi) + if(NOT ${batch_has_lowdpi} STREQUAL ${arg_LOWDPI}) + qt_internal_get_test_batch(test_batch_contents) + message(FATAL_ERROR "Conflicting lowdpi declaration between test batch \ + (${test_batch_contents}) and ${name}") + endif() + qt_internal_get_target_property(batch_version ${target} _qt_version) + if(NOT "${batch_version} " STREQUAL " " AND + NOT "${version_arg} " STREQUAL " " AND + NOT "${batch_version} " STREQUAL "${version_arg} ") + qt_internal_get_test_batch(test_batch_contents) + message(FATAL_ERROR "Conflicting version declaration between test \ + batch ${test_batch_contents} (${batch_version}) and ${name} (${version_arg})") + endif() + endif() + + get_property(batched_test_list GLOBAL PROPERTY _qt_batched_test_list_property) + if(NOT batched_test_list) + set_property(GLOBAL PROPERTY _qt_batched_test_list_property "") + set(batched_test_list "") + endif() + list(PREPEND batched_test_list ${name}) + set_property(GLOBAL PROPERTY _qt_batched_test_list_property ${batched_test_list}) + + # Test batching produces single executable which can result in one source file being added + # multiple times (with different definitions) to one translation unit. This is not supported by + # CMake so instead we try to detect such situation and rename file every time it's added + # to the build more than once. This avoids filenames collisions in one translation unit. + get_property(batched_test_sources_list GLOBAL PROPERTY _qt_batched_test_sources_list_property) + if(NOT batched_test_sources_list) + set_property(GLOBAL PROPERTY _qt_batched_test_sources_list_property "") + set(batched_test_sources_list "") + endif() + foreach(source ${arg_SOURCES}) + set(source_path ${source}) + if(${source} IN_LIST batched_test_sources_list) + set(new_filename ${name}.cpp) + configure_file(${source} ${new_filename}) + set(source_path ${CMAKE_CURRENT_BINARY_DIR}/${new_filename}) + set(skip_automoc ON) + list(APPEND arg_SOURCES ${source_path}) + else() + set(skip_automoc OFF) + list(APPEND batched_test_sources_list ${source}) + endif() + set_source_files_properties(${source_path} + TARGET_DIRECTORY ${target} PROPERTIES + SKIP_AUTOMOC ${skip_automoc} + COMPILE_DEFINITIONS "BATCHED_TEST_NAME=\"${name}\";${arg_DEFINES}") + endforeach() + set_property(GLOBAL PROPERTY _qt_batched_test_sources_list_property ${batched_test_sources_list}) + + # Merge the current test with the rest of the batch + qt_internal_extend_target(${target} + INCLUDE_DIRECTORIES ${arg_INCLUDE_DIRECTORIES} + PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES} + LIBRARIES ${arg_LIBRARIES} + SOURCES ${arg_SOURCES} + COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} + COMPILE_FLAGS ${arg_COMPILE_FLAGS} + LINK_OPTIONS ${arg_LINK_OPTIONS} + MOC_OPTIONS ${arg_MOC_OPTIONS} + ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + NO_UNITY_BUILD # Tests should not be built using UNITY_BUILD + ) + + set(${batch_name} ${target} PARENT_SCOPE) + + # Add a dummy target so that new tests don't have problems with a nonexistent + # target when calling cmake functions. + # The batch tests that include this target will compile, but may fail to work. + # Manual action is required then. + add_custom_target(${name}) + + # Add the dependency to the dummy target so that it is indirectly added to the test batch + # dependencies. + add_dependencies(${target} ${name}) +endfunction() + +# Checks whether the test 'name' is present in the test batch. See QT_BUILD_TESTS_BATCHED. +# The result of the check is placed in the 'out' variable. +function(qt_internal_is_in_test_batch out name) + set(${out} FALSE PARENT_SCOPE) + if(QT_BUILD_TESTS_BATCHED) + get_property(batched_test_list GLOBAL PROPERTY _qt_batched_test_list_property) + if("${name}" IN_LIST batched_test_list) + set(${out} TRUE PARENT_SCOPE) + endif() + endif() +endfunction() + +function(qt_internal_is_skipped_test out name) + get_target_property(is_skipped_test ${name} _qt_is_skipped_test) + set(${out} ${is_skipped_test} PARENT_SCOPE) +endfunction() + +function(qt_internal_set_skipped_test name) + set_target_properties(${name} PROPERTIES _qt_is_skipped_test TRUE) +endfunction() + +function(qt_internal_is_qtbase_test out) + get_filename_component(dir "${CMAKE_CURRENT_BINARY_DIR}" ABSOLUTE) + set(${out} FALSE PARENT_SCOPE) + + while(TRUE) + get_filename_component(filename "${dir}" NAME) + if("${filename}" STREQUAL "qtbase") + set(${out} TRUE PARENT_SCOPE) + break() + endif() + + set(prev_dir "${dir}") + get_filename_component(dir "${dir}" DIRECTORY) + if("${dir}" STREQUAL "${prev_dir}") + break() + endif() + endwhile() +endfunction() + +function(qt_internal_get_batched_test_arguments out testname) + if(WASM) + # Add a query string to the runner document, so that the script therein + # knows which test to run in response to launching the testcase by ctest. + list(APPEND args "qbatchedtest") + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + list(APPEND args "qvisualoutput") + endif() + else() + # Simply add the test name in case of standard executables. + list(APPEND args "${testname}") + endif() + set(${out} ${args} PARENT_SCOPE) +endfunction() + # This function creates a CMake test target with the specified name for use with CTest. # # All tests are wrapped with cmake script that supports TESTARGS and TESTRUNNER environment @@ -175,41 +439,81 @@ endfunction() # You may avoid test wrapping by either passing NO_WRAPPER option or switching QT_NO_TEST_WRAPPERS # to ON. This is helpful if you want to use internal CMake tools within tests, like memory or # sanitizer checks. See https://cmake.org/cmake/help/v3.19/manual/ctest.1.html#ctest-memcheck-step +# Arguments: +# BUILTIN_TESTDATA +# The option forces adding the provided TESTDATA to resources. +# MANUAL +# The option indicates that the test is a manual test. function(qt_internal_add_test name) - # EXCEPTIONS is a noop as they are enabled by default. - qt_parse_all_arguments(arg "qt_add_test" - "RUN_SERIAL;EXCEPTIONS;NO_EXCEPTIONS;GUI;QMLTEST;CATCH;LOWDPI;NO_WRAPPER" - "OUTPUT_DIRECTORY;WORKING_DIRECTORY;TIMEOUT;VERSION" - "QML_IMPORTPATH;TESTDATA;QT_TEST_SERVER_LIST;${__default_private_args};${__default_public_args}" ${ARGN} - ) + qt_internal_get_test_arg_definitions(optional_args single_value_args multi_value_args) - if (NOT arg_OUTPUT_DIRECTORY) - set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + cmake_parse_arguments(PARSE_ARGV 1 arg + "${optional_args}" + "${single_value_args}" + "${multi_value_args}" + ) + _qt_internal_validate_all_args_are_parsed(arg) + _qt_internal_validate_no_unity_build(arg) + + set(batch_current_test FALSE) + if(QT_BUILD_TESTS_BATCHED AND NOT arg_NO_BATCH AND NOT arg_QMLTEST AND NOT arg_MANUAL + AND ("${QT_STANDALONE_TEST_PATH}" STREQUAL "" + OR DEFINED ENV{QT_BATCH_STANDALONE_TESTS})) + set(batch_current_test TRUE) endif() - # Qt modules get compiled without exceptions enabled by default. - # However, testcases should be still built with exceptions. - set(exceptions_text "EXCEPTIONS") - if (${arg_NO_EXCEPTIONS}) - set(exceptions_text "") + if(batch_current_test OR (QT_BUILD_TESTS_BATCHED AND arg_QMLTEST)) + if (QT_SUPERBUILD OR DEFINED ENV{TESTED_MODULE_COIN}) + set(is_qtbase_test FALSE) + if(QT_SUPERBUILD) + qt_internal_is_qtbase_test(is_qtbase_test) + elseif($ENV{TESTED_MODULE_COIN} STREQUAL "qtbase") + set(is_qtbase_test TRUE) + endif() + if(NOT is_qtbase_test) + file(GENERATE OUTPUT "dummy${name}.cpp" CONTENT "int main() { return 0; }") + # Add a dummy target to tackle some potential problems + qt_internal_add_executable(${name} SOURCES "dummy${name}.cpp") + # Batched tests outside of qtbase are unsupported and skipped + qt_internal_set_skipped_test(${name}) + return() + endif() + endif() endif() - if (${arg_GUI}) - set(gui_text "GUI") + if(NOT arg_OUTPUT_DIRECTORY) + if(CMAKE_RUNTIME_OUTPUT_DIRECTORY) + set(arg_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") + else() + set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + endif() endif() - if (arg_VERSION) - set(version_arg VERSION "${arg_VERSION}") + set(private_includes + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" + "$<BUILD_INTERFACE:${QT_BUILD_DIR}/include>" + ) + + set(testname "${name}") + + if(arg_PUBLIC_LIBRARIES) + message(WARNING + "qt_internal_add_test's PUBLIC_LIBRARIES option is deprecated, and will be " + "removed in a future Qt version. Use the LIBRARIES option instead.") endif() - # Handle cases where we have a qml test without source files - if (arg_SOURCES) - set(private_includes - "${CMAKE_CURRENT_SOURCE_DIR}" - "${CMAKE_CURRENT_BINARY_DIR}" - "$<BUILD_INTERFACE:${QT_BUILD_DIR}/include>" - ${arg_INCLUDE_DIRECTORIES} - ) + if(batch_current_test) + qt_internal_add_test_to_batch(name ${name} ${ARGN}) + elseif(arg_SOURCES) + if(QT_BUILD_TESTS_BATCHED AND arg_QMLTEST) + message(WARNING "QML tests won't be batched - unsupported (yet)") + endif() + # Handle cases where we have a qml test without source files + list(APPEND private_includes ${arg_INCLUDE_DIRECTORIES}) + + qt_internal_prepare_test_target_flags(version_arg exceptions_text gui_text ${ARGN}) + qt_internal_library_deprecation_level(deprecation_define) qt_internal_add_executable("${name}" ${exceptions_text} @@ -222,26 +526,44 @@ function(qt_internal_add_test name) ${private_includes} DEFINES ${arg_DEFINES} - PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Core ${QT_CMAKE_EXPORT_NAMESPACE}::Test ${arg_PUBLIC_LIBRARIES} - LIBRARIES ${arg_LIBRARIES} + ${deprecation_define} + LIBRARIES + ${arg_LIBRARIES} + ${arg_PUBLIC_LIBRARIES} + ${QT_CMAKE_EXPORT_NAMESPACE}::Core + ${QT_CMAKE_EXPORT_NAMESPACE}::Test COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} LINK_OPTIONS ${arg_LINK_OPTIONS} MOC_OPTIONS ${arg_MOC_OPTIONS} ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + NO_UNITY_BUILD # Tests should not be built using UNITY_BUILD ) - # Tests should not be bundles on macOS even if arg_GUI is true, because some tests make - # assumptions about the location of helper processes, and those paths would be different - # if a test is built as a bundle. - set_property(TARGET "${name}" PROPERTY MACOSX_BUNDLE FALSE) - # The same goes for WIN32_EXECUTABLE, but because it will detach from the console window - # and not print anything. - set_property(TARGET "${name}" PROPERTY WIN32_EXECUTABLE FALSE) + qt_internal_add_repo_local_defines(${name}) + + # Disable the QT_NO_NARROWING_CONVERSIONS_IN_CONNECT define for tests + qt_internal_undefine_global_definition(${name} QT_NO_NARROWING_CONVERSIONS_IN_CONNECT) + + # Manual tests can be bundle apps + if(NOT arg_MANUAL) + # Tests should not be bundles on macOS even if arg_GUI is true, because some tests make + # assumptions about the location of helper processes, and those paths would be different + # if a test is built as a bundle. + set_property(TARGET "${name}" PROPERTY MACOSX_BUNDLE FALSE) + # The same goes for WIN32_EXECUTABLE, but because it will detach from the console window + # and not print anything. + set_property(TARGET "${name}" PROPERTY WIN32_EXECUTABLE FALSE) + endif() + + # Tests on iOS must be app bundles. + if(IOS) + set_target_properties(${name} PROPERTIES MACOSX_BUNDLE TRUE) + endif() # QMLTest specifics qt_internal_extend_target("${name}" CONDITION arg_QMLTEST - PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::QuickTest + LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::QuickTest ) qt_internal_extend_target("${name}" CONDITION arg_QMLTEST AND NOT ANDROID @@ -256,8 +578,15 @@ function(qt_internal_add_test name) # Android requires Qt::Gui so add it by default for tests qt_internal_extend_target("${name}" CONDITION ANDROID - PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Gui + LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Gui ) + set_target_properties(${name} PROPERTIES _qt_is_test_executable TRUE) + set_target_properties(${name} PROPERTIES _qt_is_manual_test ${arg_MANUAL}) + + set(blacklist_file "${CMAKE_CURRENT_SOURCE_DIR}/BLACKLIST") + if(EXISTS ${blacklist_file}) + _qt_internal_expose_source_file_to_ide("${name}" ${blacklist_file}) + endif() endif() foreach(path IN LISTS arg_QML_IMPORTPATH) @@ -283,8 +612,80 @@ function(qt_internal_add_test name) endif() if (ANDROID) - qt_internal_android_test_arguments("${name}" test_executable extra_test_args) + # Pass 95% of the timeout to allow the test runner time to do any cleanup + # before being killed. + set(percentage "95") + qt_internal_get_android_test_timeout("${arg_TIMEOUT}" "${percentage}" android_timeout) + + if(arg_BUNDLE_ANDROID_OPENSSL_LIBS) + if(EXISTS "${OPENSSL_ROOT_DIR}/${CMAKE_ANDROID_ARCH_ABI}/libcrypto_3.so") + message(STATUS "Looking for OpenSSL in ${OPENSSL_ROOT_DIR}") + set_property(TARGET ${name} APPEND PROPERTY QT_ANDROID_EXTRA_LIBS + "${OPENSSL_ROOT_DIR}/${CMAKE_ANDROID_ARCH_ABI}/libcrypto_3.so" + "${OPENSSL_ROOT_DIR}/${CMAKE_ANDROID_ARCH_ABI}/libssl_3.so") + elseif(QT_USE_VCPKG AND DEFINED ENV{VCPKG_ROOT}) + message(STATUS "Looking for OpenSSL in $ENV{VCPKG_ROOT}") + if (CMAKE_ANDROID_ARCH_ABI MATCHES "arm64-v8a") + set(coin_vcpkg_target_triplet "arm64-android-dynamic") + elseif(CMAKE_ANDROID_ARCH_ABI MATCHES "armeabi-v7a") + set(coin_vcpkg_target_triplet "arm-neon-android-dynamic") + elseif(CMAKE_ANDROID_ARCH_ABI MATCHES "x86_64") + set(coin_vcpkg_target_triplet "x64-android-dynamic") + elseif(CMAKE_ANDROID_ARCH_ABI MATCHES "x86") + set(coin_vcpkg_target_triplet "x86-android-dynamic") + endif() + if(EXISTS "$ENV{VCPKG_ROOT}/installed/${coin_vcpkg_target_triplet}/lib/libcrypto.so") + message(STATUS "Found OpenSSL in $ENV{VCPKG_ROOT}/installed/${coin_vcpkg_target_triplet}/lib") + set_property(TARGET ${name} APPEND PROPERTY QT_ANDROID_EXTRA_LIBS + "$ENV{VCPKG_ROOT}/installed/${coin_vcpkg_target_triplet}/lib/libcrypto.so" + "$ENV{VCPKG_ROOT}/installed/${coin_vcpkg_target_triplet}/lib/libssl.so") + endif() + else() + message(STATUS "The argument BUNDLE_ANDROID_OPENSSL_LIBS is set " + "but OPENSSL_ROOT_DIR parameter is not set. " + "Test should bundle OpenSSL libraries but they are not found. " + "This is fine if OpenSSL was built statically.") + endif() + endif() + qt_internal_android_test_arguments( + "${name}" "${android_timeout}" test_executable extra_test_args) set(test_working_dir "${CMAKE_CURRENT_BINARY_DIR}") + elseif(QNX) + set(test_working_dir "") + set(test_executable "${name}") + elseif(WASM) + # The test script expects an html file. In case of batched tests, the + # version specialized for running batches has to be supplied. + if(batch_current_test) + get_target_property(batch_output_dir ${name} RUNTIME_OUTPUT_DIRECTORY) + set(test_executable "${batch_output_dir}/${name}.html") + else() + set(test_executable "${name}.html") + endif() + + list(APPEND extra_test_args "quseemrun") + list(APPEND extra_test_args "qtestname=${testname}") + list(APPEND extra_test_args "--silence_timeout=60") + # TODO: Add functionality to specify browser + list(APPEND extra_test_args "--browser=chrome") + list(APPEND extra_test_args "--browser_args=\"--password-store=basic\"") + list(APPEND extra_test_args "--kill_exit") + + # Tests may require asyncify if they use exec(). Enable asyncify for + # batched tests since this is the configuration used on the CI system. + # Optimize for size (-Os), since asyncify tends to make the resulting + # binary very large + if(batch_current_test) + target_link_options("${name}" PRIVATE "SHELL:-s ASYNCIFY" "-Os") + endif() + + # This tells cmake to run the tests with this script, since wasm files can't be + # executed directly + if (CMAKE_HOST_WIN32) + set_property(TARGET "${name}" PROPERTY CROSSCOMPILING_EMULATOR "emrun.bat") + else() + set_property(TARGET "${name}" PROPERTY CROSSCOMPILING_EMULATOR "emrun") + endif() else() if(arg_QMLTEST AND NOT arg_SOURCES) set(test_working_dir "${CMAKE_CURRENT_SOURCE_DIR}") @@ -301,49 +702,79 @@ function(qt_internal_add_test name) endif() endif() - qt_internal_collect_command_environment(test_env_path test_env_plugin_path) + if(NOT arg_MANUAL) + if(batch_current_test) + qt_internal_get_batched_test_arguments(batched_test_args ${testname}) + list(PREPEND extra_test_args ${batched_test_args}) + elseif(WASM AND CMAKE_BUILD_TYPE STREQUAL "Debug") + list(PREPEND extra_test_args "qvisualoutput") + endif() - if(arg_NO_WRAPPER OR QT_NO_TEST_WRAPPERS) - add_test(NAME "${name}" COMMAND ${test_executable} ${extra_test_args} - WORKING_DIRECTORY "${test_working_dir}") - set_property(TEST "${name}" APPEND PROPERTY - ENVIRONMENT "PATH=${test_env_path}" - "QT_TEST_RUNNING_IN_CTEST=1" - "QT_PLUGIN_PATH=${test_env_plugin_path}" - ) - else() - set(test_wrapper_file "${CMAKE_CURRENT_BINARY_DIR}/${name}Wrapper$<CONFIG>.cmake") - qt_internal_create_test_script(NAME "${name}" - COMMAND "${test_executable}" - ARGS "${extra_test_args}" - WORKING_DIRECTORY "${test_working_dir}" - OUTPUT_FILE "${test_wrapper_file}" - ENVIRONMENT "QT_TEST_RUNNING_IN_CTEST" 1 - "PATH" "${test_env_path}" - "QT_PLUGIN_PATH" "${test_env_plugin_path}" - ) - endif() + qt_internal_collect_command_environment(test_env_path test_env_plugin_path) - if(arg_QT_TEST_SERVER_LIST AND NOT ANDROID) - qt_internal_setup_docker_test_fixture(${name} ${arg_QT_TEST_SERVER_LIST}) - endif() + if(arg_NO_WRAPPER OR QT_NO_TEST_WRAPPERS) + if(QT_BUILD_TESTS_BATCHED) + message(FATAL_ERROR "Wrapperless tests are unspupported with test batching") + endif() - set_tests_properties("${name}" PROPERTIES RUN_SERIAL "${arg_RUN_SERIAL}" LABELS "${label}") - if (arg_TIMEOUT) - set_tests_properties(${name} PROPERTIES TIMEOUT ${arg_TIMEOUT}) - endif() + add_test(NAME "${testname}" COMMAND ${test_executable} ${extra_test_args} + WORKING_DIRECTORY "${test_working_dir}") + set_property(TEST "${testname}" APPEND PROPERTY + ENVIRONMENT "PATH=${test_env_path}" + "QT_TEST_RUNNING_IN_CTEST=1" + "QT_PLUGIN_PATH=${test_env_plugin_path}" + ) + else() + set(test_wrapper_file "${CMAKE_CURRENT_BINARY_DIR}/${testname}Wrapper$<CONFIG>.cmake") + qt_internal_create_test_script(NAME "${testname}" + COMMAND "${test_executable}" + ARGS "${extra_test_args}" + WORKING_DIRECTORY "${test_working_dir}" + OUTPUT_FILE "${test_wrapper_file}" + ENVIRONMENT "QT_TEST_RUNNING_IN_CTEST" 1 + "PATH" "${test_env_path}" + "QT_PLUGIN_PATH" "${test_env_plugin_path}" + ) + endif() - # Add a ${target}/check makefile target, to more easily test one test. - add_custom_target("${name}_check" - VERBATIM - COMMENT "Running ${CMAKE_CTEST_COMMAND} -V -R \"^${name}$\"" - COMMAND "${CMAKE_CTEST_COMMAND}" -V -R "^${name}$" - ) - if(TARGET "${name}") - add_dependencies("${name}_check" "${name}") + if(arg_QT_TEST_SERVER_LIST AND NOT ANDROID) + qt_internal_setup_docker_test_fixture(${testname} ${arg_QT_TEST_SERVER_LIST}) + endif() + + set_tests_properties("${testname}" PROPERTIES RUN_SERIAL "${arg_RUN_SERIAL}" LABELS "${label}") + if(arg_TIMEOUT) + set_tests_properties(${testname} PROPERTIES TIMEOUT ${arg_TIMEOUT}) + endif() + + if(ANDROID AND NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") + # Set timeout signal and some time for androidtestrunner to do cleanup + set_tests_properties(${testname} PROPERTIES + TIMEOUT_SIGNAL_NAME "SIGINT" + TIMEOUT_SIGNAL_GRACE_PERIOD 10.0 + ) + endif() + + # Add a ${target}/check makefile target, to more easily test one test. + + set(test_config_options "") + get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) + if(is_multi_config) + set(test_config_options -C $<CONFIG>) + endif() + add_custom_target("${testname}_check" + VERBATIM + COMMENT "Running ${CMAKE_CTEST_COMMAND} -V -R \"^${name}$\" ${test_config_options}" + COMMAND "${CMAKE_CTEST_COMMAND}" -V -R "^${name}$" ${test_config_options} + ) + if(TARGET "${name}") + add_dependencies("${testname}_check" "${name}") + if(ANDROID) + add_dependencies("${testname}_check" "${name}_make_apk") + endif() + endif() endif() - if(ANDROID OR IOS OR WINRT) + if(ANDROID OR IOS OR WASM OR INTEGRITY OR arg_BUILTIN_TESTDATA) set(builtin_testdata TRUE) endif() @@ -355,10 +786,29 @@ function(qt_internal_add_test name) foreach(testdata IN LISTS arg_TESTDATA) list(APPEND builtin_files ${testdata}) endforeach() + foreach(file IN LISTS builtin_files) + set_source_files_properties(${file} + PROPERTIES QT_SKIP_QUICKCOMPILER TRUE + ) + endforeach() - set(blacklist_path "BLACKLIST") - if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}") - list(APPEND builtin_files ${blacklist_path}) + if(batch_current_test) + set(blacklist_path "BLACKLIST") + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}") + get_target_property(blacklist_files ${name} _qt_blacklist_files) + if(NOT blacklist_files) + set_target_properties(${name} PROPERTIES _qt_blacklist_files "") + set(blacklist_files "") + cmake_language(EVAL CODE "cmake_language(DEFER DIRECTORY \"${CMAKE_SOURCE_DIR}\" CALL \"_qt_internal_finalize_batch\" \"${name}\") ") + endif() + list(PREPEND blacklist_files "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}") + set_target_properties(${name} PROPERTIES _qt_blacklist_files "${blacklist_files}") + endif() + else() + set(blacklist_path "BLACKLIST") + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}") + list(APPEND builtin_files ${blacklist_path}) + endif() endif() list(REMOVE_DUPLICATES builtin_files) @@ -370,23 +820,35 @@ function(qt_internal_add_test name) ) endforeach() - if (builtin_files) - qt_internal_add_resource(${name} "${name}_testdata_builtin" + if(builtin_files) + qt_internal_add_resource(${name} "${testname}_testdata_builtin" PREFIX "/" FILES ${builtin_files} BASE ${CMAKE_CURRENT_SOURCE_DIR}) endif() endif() else() - # Install test data - file(RELATIVE_PATH relative_path_to_test_project - "${QT_TOP_LEVEL_SOURCE_DIR}" - "${CMAKE_CURRENT_SOURCE_DIR}") - qt_path_join(testdata_install_dir ${QT_INSTALL_DIR} - "${relative_path_to_test_project}") - if (testdata_install_dir) + # Install test data, when tests are built in-tree or as standalone tests, but not as a + # single standalone test, which is checked by the existence of the QT_TOP_LEVEL_SOURCE_DIR + # variable. + # TODO: Shouldn't we also handle the single standalone test case? + # TODO: Does installing even makes sense, given where QFINDTESTDATA looks for installed + # test data, and where we end up installing it? See QTBUG-117098. + if(QT_TOP_LEVEL_SOURCE_DIR) foreach(testdata IN LISTS arg_TESTDATA) set(testdata "${CMAKE_CURRENT_SOURCE_DIR}/${testdata}") + + # Get the relative source dir for each test data entry, because it might contain a + # subdirectory. + file(RELATIVE_PATH relative_path_to_test_project + "${QT_TOP_LEVEL_SOURCE_DIR}" + "${testdata}") + get_filename_component(relative_path_to_test_project + "${relative_path_to_test_project}" DIRECTORY) + + qt_path_join(testdata_install_dir ${QT_INSTALL_DIR} + "${relative_path_to_test_project}") + if (IS_DIRECTORY "${testdata}") qt_install( DIRECTORY "${testdata}" @@ -400,6 +862,36 @@ function(qt_internal_add_test name) endif() endif() + qt_internal_add_test_finalizers("${name}") +endfunction() + +# Given an optional test timeout value (specified via qt_internal_add_test's TIMEOUT option) +# returns a percentage of the final timeout to be passed to the androidtestrunner executable. +# +# When the optional timeout is empty, default to cmake's defaults for getting the timeout. +function(qt_internal_get_android_test_timeout input_timeout percentage output_timeout_var) + set(actual_timeout "${input_timeout}") + if(NOT actual_timeout) + # we have coin ci timeout set use that to avoid having the emulator killed + # so we can at least get some logs from the android test runner. + set(coin_timeout $ENV{COIN_COMMAND_OUTPUT_TIMEOUT}) + if(coin_timeout) + set(actual_timeout "${coin_timeout}") + elseif(DART_TESTING_TIMEOUT) + # Related: https://gitlab.kitware.com/cmake/cmake/-/issues/20450 + set(actual_timeout "${DART_TESTING_TIMEOUT}") + elseif(CTEST_TEST_TIMEOUT) + set(actual_timeout "${CTEST_TEST_TIMEOUT}") + else() + # Default DART_TESTING_TIMEOUT is 25 minutes, specified in seconds + # https://github.com/Kitware/CMake/blob/master/Modules/CTest.cmake#L167C16-L167C16 + set(actual_timeout "1500") + endif() + endif() + + math(EXPR calculated_timeout "${actual_timeout} * ${percentage} / 100") + + set(${output_timeout_var} "${calculated_timeout}" PARENT_SCOPE) endfunction() # This function adds test with specified NAME and wraps given test COMMAND with standalone cmake @@ -410,7 +902,7 @@ endfunction() # directly by 'cmake -P path/to/scriptWrapper.cmake', COMMAND will be executed in specified # WORKING_DIRECTORY with arguments specified in ARGS. # -# See also qt_internal_create_command_script for details. +# See also _qt_internal_create_command_script for details. function(qt_internal_create_test_script) #This style of parsing keeps ';' in ENVIRONMENT variables cmake_parse_arguments(PARSE_ARGV 0 arg @@ -454,6 +946,11 @@ for this function. Will be ignored") set(executable_file "${arg_COMMAND}") endif() + set(executable_name ${arg_NAME}) + qt_internal_is_in_test_batch(is_in_batch ${executable_name}) + if(is_in_batch) + _qt_internal_test_batch_target_name(executable_name) + endif() add_test(NAME "${arg_NAME}" COMMAND "${CMAKE_COMMAND}" "-P" "${arg_OUTPUT_FILE}" WORKING_DIRECTORY "${arg_WORKING_DIRECTORY}") @@ -461,8 +958,9 @@ for this function. Will be ignored") # Prepend emulator to test command in generated cmake script instead. Keep in mind that # CROSSCOMPILING_EMULATOR don't check if actual cross compilation is configured, # emulator is prepended independently. - if(CMAKE_CROSSCOMPILING) - get_test_property(${arg_NAME} CROSSCOMPILING_EMULATOR crosscompiling_emulator) + set(crosscompiling_emulator "") + if(CMAKE_CROSSCOMPILING AND TARGET ${executable_name}) + get_target_property(crosscompiling_emulator ${executable_name} CROSSCOMPILING_EMULATOR) if(NOT crosscompiling_emulator) set(crosscompiling_emulator "") else() @@ -470,7 +968,7 @@ for this function. Will be ignored") endif() endif() - qt_internal_create_command_script(COMMAND "${crosscompiling_emulator} \${env_test_runner} \ + _qt_internal_create_command_script(COMMAND "${crosscompiling_emulator} \${env_test_runner} \ \"${executable_file}\" \${env_test_args} ${command_args}" OUTPUT_FILE "${arg_OUTPUT_FILE}" WORKING_DIRECTORY "${arg_WORKING_DIRECTORY}" @@ -482,103 +980,11 @@ for this function. Will be ignored") ) endfunction() -# This function wraps COMMAND with cmake script, that makes possible standalone run with external -# arguments. -# -# Generated wrapper will be written to OUTPUT_FILE. -# If WORKING_DIRECTORY is not set COMMAND will be executed in CMAKE_CURRENT_BINARY_DIR. -# Variables from ENVIRONMENT will be set before COMMAND execution. -# PRE_RUN and POST_RUN arguments may contain extra cmake code that supposed to be executed before -# and after COMMAND, respectively. Both arguments accept a list of cmake script language -# constructions. Each item of the list will be concantinated into single string with '\n' sepatator. -function(qt_internal_create_command_script) - #This style of parsing keeps ';' in ENVIRONMENT variables - cmake_parse_arguments(PARSE_ARGV 0 arg - "" - "OUTPUT_FILE;WORKING_DIRECTORY" - "COMMAND;ENVIRONMENT;PRE_RUN;POST_RUN" - ) - - if(NOT arg_COMMAND) - message(FATAL_ERROR "qt_internal_create_command_script: COMMAND is not specified") - endif() - if(NOT arg_OUTPUT_FILE) - message(FATAL_ERROR "qt_internal_create_command_script: Wrapper OUTPUT_FILE\ -is not specified") - endif() - - if(NOT arg_WORKING_DIRECTORY) - set(arg_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") - endif() - - set(environment_extras) - set(skipNext false) - if(arg_ENVIRONMENT) - list(LENGTH arg_ENVIRONMENT length) - math(EXPR length "${length} - 1") - foreach(envIdx RANGE ${length}) - if(skipNext) - set(skipNext FALSE) - continue() - endif() - - set(envVariable "") - set(envValue "") - - list(GET arg_ENVIRONMENT ${envIdx} envVariable) - math(EXPR envIdx "${envIdx} + 1") - if (envIdx LESS_EQUAL ${length}) - list(GET arg_ENVIRONMENT ${envIdx} envValue) - endif() - - if(NOT "${envVariable}" STREQUAL "") - set(environment_extras "${environment_extras}\nset(ENV{${envVariable}} \ -\"${envValue}\")") - endif() - set(skipNext TRUE) - endforeach() - endif() - - #Escaping environment variables before expand them by file GENERATE - string(REPLACE "\\" "\\\\" environment_extras "${environment_extras}") - - if(WIN32) - # It's necessary to call actual test inside 'cmd.exe', because 'execute_process' uses - # SW_HIDE to avoid showing a console window, it affects other GUI as well. - # See https://gitlab.kitware.com/cmake/cmake/-/issues/17690 for details. - set(extra_runner "cmd /c") - endif() - - if(arg_PRE_RUN) - string(JOIN "\n" pre_run ${arg_PRE_RUN}) - endif() - - if(arg_POST_RUN) - string(JOIN "\n" post_run ${arg_POST_RUN}) - endif() - - file(GENERATE OUTPUT "${arg_OUTPUT_FILE}" CONTENT -"#!${CMAKE_COMMAND} -P -# Qt generated command wrapper - -${environment_extras} -${pre_run} -execute_process(COMMAND ${extra_runner} ${arg_COMMAND} - WORKING_DIRECTORY \"${arg_WORKING_DIRECTORY}\" - RESULT_VARIABLE result -) -${post_run} -if(NOT result EQUAL 0) - string(JOIN \" \" full_command ${arg_COMMAND}) - message(FATAL_ERROR \"\${full_command} execution failed.\") -endif()" - ) -endfunction() # This function creates an executable for use as a helper program with tests. Some # tests launch separate programs to test certain input/output behavior. -# Specify OVERRIDE_OUTPUT_DIRECTORY if you dont' want to place the helper in the parent directory, +# Specify OVERRIDE_OUTPUT_DIRECTORY if you don't want to place the helper in the parent directory, # in which case you should specify OUTPUT_DIRECTORY "/foo/bar" manually. function(qt_internal_add_test_helper name) @@ -586,11 +992,12 @@ function(qt_internal_add_test_helper name) "OVERRIDE_OUTPUT_DIRECTORY" ) - qt_parse_all_arguments(arg "qt_add_test_helper" + cmake_parse_arguments(PARSE_ARGV 1 arg "${qt_add_test_helper_optional_args};${__qt_internal_add_executable_optional_args}" "${__qt_internal_add_executable_single_args}" "${__qt_internal_add_executable_multi_args}" - ${ARGN}) + ) + _qt_internal_validate_all_args_are_parsed(arg) qt_remove_args(forward_args ARGS_TO_REMOVE @@ -607,10 +1014,23 @@ function(qt_internal_add_test_helper name) set(extra_args_to_pass) if(NOT arg_OVERRIDE_OUTPUT_DIRECTORY) - set(extra_args_to_pass OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/..") + _qt_internal_test_batch_target_name(test_batch_target_name) + if(QT_BUILD_TESTS_BATCHED AND TARGET ${test_batch_target_name}) + get_target_property( + test_batch_output_dir ${test_batch_target_name} RUNTIME_OUTPUT_DIRECTORY) + set(extra_args_to_pass OUTPUT_DIRECTORY "${test_batch_output_dir}") + else() + set(extra_args_to_pass OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/..") + endif() endif() - qt_internal_add_executable("${name}" NO_INSTALL ${extra_args_to_pass} ${forward_args}) + qt_internal_add_executable("${name}" NO_INSTALL + NO_UNITY_BUILD # excluded by default + ${extra_args_to_pass} ${forward_args}) + + # Disable the QT_NO_NARROWING_CONVERSIONS_IN_CONNECT define for test helpers + qt_internal_undefine_global_definition(${name} QT_NO_NARROWING_CONVERSIONS_IN_CONNECT) + endfunction() function(qt_internal_wrap_command_arguments argument_list) @@ -658,3 +1078,14 @@ function(qt_internal_collect_command_environment out_path out_plugin_path) string(REPLACE ";" "\;" plugin_paths_joined "${plugin_paths_joined}") set(${out_plugin_path} "${plugin_paths_joined}" PARENT_SCOPE) endfunction() + +function(qt_internal_add_test_finalizers target) + # It might not be safe to run all the finalizers of _qt_internal_finalize_executable + # within the context of a Qt build (not a user project) when targeting a host build. + # At least one issue is missing qmlimportscanner at configure time. + # For now, we limit it to iOS, where it was tested to work, an we know that host tools + # should already be built and available. + if(IOS) + qt_add_list_file_finalizer(_qt_internal_finalize_executable "${target}") + endif() +endfunction() |