diff --git a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake index 1427f5a5fcb..8cbd0b566f2 100644 --- a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake +++ b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake @@ -372,11 +372,6 @@ macro(qt_build_repo_begin) qt_build_internals_set_up_private_api() qt_enable_cmake_languages() - # QtBase has own call right after definition of internal platform-specific targets. - if(NOT PROJECT_NAME STREQUAL "QtBase") - qt_internal_run_common_config_tests() - endif() - # Add global docs targets that will work both for per-repo builds, and super builds. if(NOT TARGET docs) add_custom_target(docs) @@ -950,24 +945,20 @@ if ("STANDALONE_TEST" IN_LIST Qt6BuildInternals_FIND_COMPONENTS) endif() function(qt_internal_static_link_order_test) - if(TARGET ${QT_CMAKE_EXPORT_NAMESPACE}::PlatformCommonInternal) - get_target_property(linker_options - ${QT_CMAKE_EXPORT_NAMESPACE}::PlatformCommonInternal INTERFACE_LINK_OPTIONS - ) - string(JOIN " " linker_options ${linker_options}) - endif() - - qt_config_compile_test(static_link_order - LABEL "Check if linker can resolve circular dependencies" - PROJECT_PATH "${QT_CMAKE_DIR}/config.tests/static_link_order" - CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${linker_options}" - ) - - if(TEST_static_link_order) - set_property(GLOBAL PROPERTY QT_LINK_ORDER_MATTERS FALSE) - set(summary_message "no") + # The CMake versions greater than 3.21 take care about the resource object files order in a + # linker line, it's expected that all object files are located at the beginning of the linker + # line. + # No need to run the test. + # TODO: This check is added before the actual release of CMake 3.21. So need to check if the + # target version meets the expectations. + if(CMAKE_VERSION VERSION_LESS 3.21) + __qt_internal_check_link_order_matters(${QT_CMAKE_EXPORT_NAMESPACE}::Platform) + if(link_order_matters) + set(summary_message "no") + else() + set(summary_message "yes") + endif() else() - set_property(GLOBAL PROPERTY QT_LINK_ORDER_MATTERS TRUE) set(summary_message "yes") endif() qt_configure_add_summary_entry(TYPE "message" diff --git a/cmake/QtConfig.cmake.in b/cmake/QtConfig.cmake.in index 98c06a46f20..35cd3f77ca0 100644 --- a/cmake/QtConfig.cmake.in +++ b/cmake/QtConfig.cmake.in @@ -61,6 +61,10 @@ include("${CMAKE_CURRENT_LIST_DIR}/QtPublicTargetHelpers.cmake") include("${CMAKE_CURRENT_LIST_DIR}/QtPublicWalkLibsHelpers.cmake") include("${CMAKE_CURRENT_LIST_DIR}/QtPublicFindPackageHelpers.cmake") +if(NOT DEFINED QT_CMAKE_EXPORT_NAMESPACE) + set(QT_CMAKE_EXPORT_NAMESPACE @QT_CMAKE_EXPORT_NAMESPACE@) +endif() + # Find required dependencies, if any. include(CMakeFindDependencyMacro) if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@Dependencies.cmake") @@ -107,3 +111,4 @@ if (_Qt_NOTFOUND_MESSAGE) endif() __qt_internal_defer_promote_targets_in_dir_scope_to_global() +__qt_internal_check_link_order_matters(@INSTALL_CMAKE_NAMESPACE@::Platform) diff --git a/cmake/QtModuleHelpers.cmake b/cmake/QtModuleHelpers.cmake index 31c45f11d32..703ddde21b0 100644 --- a/cmake/QtModuleHelpers.cmake +++ b/cmake/QtModuleHelpers.cmake @@ -575,14 +575,6 @@ set(QT_LIBINFIX \"${QT_LIBINFIX}\")") set(extra_cmake_code "") - if(target STREQUAL Core) - # Propagate non-build related variables that are needed for consuming Qt packages. - # Do this in CoreConfig instead of Qt6Config, so that consumers can also use - # find_package(Qt6Core) instead of find_package(Qt6 COMPONENTS Core) - string(APPEND extra_cmake_code " -set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})") - endif() - # Generate metatypes if(${arg_GENERATE_METATYPES}) # No mention of NO_GENERATE_METATYPES. You should not use it. diff --git a/cmake/QtPublicFinalizerHelpers.cmake b/cmake/QtPublicFinalizerHelpers.cmake index 24354654c8f..365d4f2a473 100644 --- a/cmake/QtPublicFinalizerHelpers.cmake +++ b/cmake/QtPublicFinalizerHelpers.cmake @@ -4,8 +4,8 @@ function(__qt_internal_check_finalizer_mode target out_var finalizer) get_target_property(value ${target} _qt_${finalizer}_finalizer_mode) if("${value}" STREQUAL "value-NOTFOUND") - set_property(TARGET "${target}" PROPERTY _qt_${finalizer}_finalizer_mode "TRUE") - set(value TRUE) + __qt_internal_enable_finalizer_mode(${target} ${finalizer} "TRUE") + set(value "TRUE") endif() set(${out_var} "${value}" PARENT_SCOPE) endfunction() diff --git a/cmake/QtPublicTargetHelpers.cmake b/cmake/QtPublicTargetHelpers.cmake index 25e8616ac44..c5e9ce7b639 100644 --- a/cmake/QtPublicTargetHelpers.cmake +++ b/cmake/QtPublicTargetHelpers.cmake @@ -15,14 +15,115 @@ function(__qt_internal_strip_target_directory_scope_token target out_var) set("${out_var}" "${target}" PARENT_SCOPE) endfunction() +# Tests if linker could resolve circular dependencies between object files and static libraries. +function(__qt_internal_static_link_order_public_test target result) + # We could trust iOS linker + if(IOS) + set(QT_HAVE_LINK_ORDER_MATTERS_${target} "FALSE" CACHE BOOL "Link order matters") + endif() + + if(DEFINED QT_HAVE_LINK_ORDER_MATTERS_${target}) + set(${result} "${QT_HAVE_LINK_ORDER_MATTERS_${target}}" PARENT_SCOPE) + return() + endif() + + set(link_options_property LINK_OPTIONS) + set(compile_definitions_property COMPILE_DEFINITIONS) + get_target_property(type ${target} TYPE) + if(type STREQUAL "INTERFACE_LIBRARY") + set(link_options_property INTERFACE_LINK_OPTIONS) + set(compile_definitions_property INTERFACE_COMPILE_DEFINITIONS) + endif() + + get_target_property(linker_options ${target} ${link_options_property}) + get_target_property(compile_definitions ${target} ${compile_definitions_property}) + set(linker_options "${CMAKE_EXE_LINKER_FLAGS} ${linker_options}") + set(compile_definitions "${CMAKE_CXX_FLAGS} ${compile_definitions}") + + if(EXISTS "${QT_CMAKE_DIR}") + set(test_source_basedir "${QT_CMAKE_DIR}") + else() + set(test_source_basedir "${_qt_cmake_dir}/${QT_CMAKE_EXPORT_NAMESPACE}") + endif() + + set(test_subdir "${target}") + string(TOLOWER "${test_subdir}" test_subdir) + string(MAKE_C_IDENTIFIER "${test_subdir}" test_subdir) + try_compile(${result} + "${CMAKE_CURRENT_BINARY_DIR}/${test_subdir}/config.tests/static_link_order" + "${test_source_basedir}/config.tests/static_link_order" + static_link_order_test + static_link_order_test + CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${linker_options}" + "-DCMAKE_CXX_FLAGS:STRING=${compile_definitions}" + ) + message(STATUS "Check if linker can resolve circular dependencies for target ${target} \ +- ${${result}}") + + # Invert the result + if(${result}) + set(${result} FALSE) + else() + set(${result} TRUE) + endif() + + set(QT_HAVE_LINK_ORDER_MATTERS_${target} "${${result}}" CACHE BOOL "Link order matters") + + set(${result} "${${result}}" PARENT_SCOPE) +endfunction() + +# Sets _qt_link_order_matters flag for the target. +function(__qt_internal_set_link_order_matters target link_order_matters) + if(NOT TARGET ${target}) + message(FATAL_ERROR "Unable to set _qt_link_order_matters flag. ${target} is not a target.") + endif() + + get_target_property(aliased_target ${target} ALIASED_TARGET) + if(aliased_target) + set(target "${aliased_target}") + endif() + + if(link_order_matters) + set(link_order_matters TRUE) + else() + set(link_order_matters FALSE) + endif() + set_target_properties(${target} PROPERTIES _qt_link_order_matters "${link_order_matters}") +endfunction() + +# Function combines __qt_internal_static_link_order_public_test and +# __qt_internal_set_link_order_matters calls for the target. +function(__qt_internal_check_link_order_matters target) + __qt_internal_static_link_order_public_test( + ${target} link_order_matters + ) + __qt_internal_set_link_order_matters( + ${target} "${link_order_matters}" + ) +endfunction() + function(__qt_internal_process_dependency_resource_objects target) + # The CMake versions greater than 3.21 take care about the resource object files order in a + # linker line, it's expected that all object files are located at the beginning of the linker + # line. + # So circular dependencies between static libraries and object files are resolved and no need + # to call the finalizer code. + # TODO: This check is added before the actual release of CMake 3.21. So need to confirm that the + # target version meets the expectations. + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21) + return() + endif() get_target_property(processed ${target} _qt_resource_object_finalizers_processed) if(processed) return() endif() set_target_properties(${target} PROPERTIES _qt_resource_object_finalizers_processed TRUE) - __qt_internal_check_finalizer_mode(${target} use_finalizer_mode resource_objects) + __qt_internal_check_finalizer_mode(${target} + use_finalizer_mode + resource_objects + ) + if(NOT use_finalizer_mode) return() endif() diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake index 3c154f4587b..2b1344766e3 100644 --- a/src/corelib/Qt6CoreMacros.cmake +++ b/src/corelib/Qt6CoreMacros.cmake @@ -592,7 +592,7 @@ function(_qt_internal_finalize_executable target) # dependencies the target has, but those might be added later than the qt_add_executable call. # Most of our examples are like that. Only enable finalizer mode when we are sure that the user # manually called qt_finalize_target at the end of their CMake project, or it was automatically - # done via a deferred call. + # done via a deferred call. This is also applicable to the resource object finalizer. get_target_property(is_immediately_finalized "${target}" _qt_is_immediately_finalized) if(NOT is_immediately_finalized) __qt_internal_apply_plugin_imports_finalizer_mode("${target}") @@ -1471,7 +1471,7 @@ function(__qt_propagate_generated_resource target resource_name generated_source ) # Keep the implicit linking if finalizers are not used. - set(finalizer_mode_condition + set(not_finalizer_mode_condition "$>>" ) # Do not litter the static libraries @@ -1480,22 +1480,38 @@ function(__qt_propagate_generated_resource target resource_name generated_source ) set(resource_objects "$>") - set(resource_linking_args ${target} INTERFACE - "$<$:${resource_objects}>" + set(platform_link_order_property + "$" + ) + set(platform_link_order_condition + "$" ) - # TODO: The QT_LINK_ORDER_MATTERS flag is not defined for user projects. - # It makes sense to disable finalizers if linker may resolve circular dependencies - # between objects and static libraries. - # Follow-up changes should set _qt_resource_objects_finalizer_mode to FALSE by default - # and use target_link_libraries for user projects if the order doesn't affect the - # linker work. - get_property(link_order_matters GLOBAL PROPERTY QT_LINK_ORDER_MATTERS) - if(link_order_matters) - target_sources(${resource_linking_args}) - else() - target_link_libraries(${resource_linking_args}) - endif() + string(JOIN "" target_sources_genex + "$<" + "$" + ":${resource_objects}>" + ) + target_sources(${target} INTERFACE + "${target_sources_genex}" + ) + + string(JOIN "" target_link_libraries_genex + "$<" + "$" + ">" + ":${resource_objects}>" + ) + target_link_libraries(${target} INTERFACE + "${target_link_libraries_genex}" + ) if(NOT target STREQUAL "Core") # It's necessary to link the object library target, since we want to pass diff --git a/tests/auto/cmake/test_static_resources/test_static_resources_propagation/CMakeLists.txt b/tests/auto/cmake/test_static_resources/test_static_resources_propagation/CMakeLists.txt index f8f46e14f4b..58a7c4147a9 100644 --- a/tests/auto/cmake/test_static_resources/test_static_resources_propagation/CMakeLists.txt +++ b/tests/auto/cmake/test_static_resources/test_static_resources_propagation/CMakeLists.txt @@ -58,9 +58,13 @@ add_test(NAME test_static_resources_propagation_non_qt COMMAND test_static_resources_propagation_non_qt ) -get_property(link_order_matters GLOBAL PROPERTY QT_LINK_ORDER_MATTERS) +get_target_property(link_order_matters + ${QT_CMAKE_EXPORT_NAMESPACE}::Platform + _qt_link_order_matters +) + if(NOT link_order_matters) - ## Add the executable using add_executable, expecting resources to be linked regardless of order. + # Add the executable using add_executable, expecting resources to be linked regardless of order. add_executable(test_static_resources_propagation_non_ld main.cpp) set_target_properties(test_static_resources_propagation_non_ld PROPERTIES AUTOMOC TRUE