diff --git a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake index 2547282dca5..8fa0e69c3eb 100644 --- a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake +++ b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake @@ -977,8 +977,27 @@ function(qt_internal_static_link_order_test) ) endfunction() +function(qt_internal_check_cmp0099_available) + # Don't care about CMP0099 in CMake versions greater than or equal to 3.21 + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21) + return() + endif() + + __qt_internal_check_cmp0099_available(result) + if(result) + set(summary_message "yes") + else() + set(summary_message "no") + endif() + qt_configure_add_summary_entry(TYPE "message" + ARGS "CMake policy CMP0099 is supported" + MESSAGE "${summary_message}" + ) +endfunction() + function(qt_internal_run_common_config_tests) qt_configure_add_summary_section(NAME "Common build options") qt_internal_static_link_order_test() + qt_internal_check_cmp0099_available() qt_configure_end_summary_section() endfunction() diff --git a/cmake/QtConfig.cmake.in b/cmake/QtConfig.cmake.in index cc3b2d7fced..92e47a04a03 100644 --- a/cmake/QtConfig.cmake.in +++ b/cmake/QtConfig.cmake.in @@ -126,4 +126,7 @@ if (_Qt_NOTFOUND_MESSAGE) endif() __qt_internal_defer_promote_targets_in_dir_scope_to_global() -__qt_internal_check_link_order_matters() +if(CMAKE_VERSION VERSION_LESS 3.21) + __qt_internal_check_link_order_matters() + __qt_internal_check_cmp0099_available() +endif() diff --git a/cmake/QtPublicTargetHelpers.cmake b/cmake/QtPublicTargetHelpers.cmake index a116d2dd5df..b84a8748802 100644 --- a/cmake/QtPublicTargetHelpers.cmake +++ b/cmake/QtPublicTargetHelpers.cmake @@ -87,6 +87,37 @@ function(__qt_internal_check_link_order_matters) endif() endfunction() +# Constructs a TARGET_POLICY genex expression if the policy is available. +function(__qt_internal_get_cmp0099_genex_check result) + if(POLICY CMP0099) + set(${result} "$>" PARENT_SCOPE) + else() + set(${result} "$" PARENT_SCOPE) + endif() +endfunction() + +function(__qt_internal_check_cmp0099_available) + set(platform_target ${QT_CMAKE_EXPORT_NAMESPACE}::Platform) + get_target_property(aliased_target ${platform_target} ALIASED_TARGET) + if(aliased_target) + set(platform_target "${aliased_target}") + endif() + + __qt_internal_get_cmp0099_genex_check(cmp0099_check) + set_target_properties(${platform_target} PROPERTIES + _qt_cmp0099_policy_check "${cmp0099_check}" + ) + + set(result TRUE) + if(NOT POLICY CMP0099) + set(result FALSE) + endif() + + if("${ARGC}" GREATER "0" AND NOT ARGV0 STREQUAL "") + set(${ARGV0} ${result} PARENT_SCOPE) + endif() +endfunction() + function(__qt_internal_process_dependency_object_libraries target) # The CMake versions greater than 3.21 take care about the order of object files in a # linker line, it's expected that all object files are located at the beginning of the linker @@ -134,17 +165,19 @@ function(__qt_internal_collect_dependency_object_libraries target out_var) ) set_property(GLOBAL PROPERTY _qt_processed_object_libraries "") + __qt_internal_get_cmp0099_genex_check(cmp0099_check) list(REMOVE_DUPLICATES object_libraries) set(objects "") foreach(dep IN LISTS object_libraries) - list(PREPEND objects "$") + list(PREPEND objects "$<$:$>") endforeach() set(${out_var} "${plugin_objects};${objects}" PARENT_SCOPE) endfunction() function(__qt_internal_collect_dependency_plugin_object_libraries target plugin_targets out_var) + __qt_internal_get_cmp0099_genex_check(cmp0099_check) set(plugin_objects "") foreach(plugin_target IN LISTS plugin_targets) __qt_internal_collect_object_libraries_recursively(plugin_object_libraries @@ -154,9 +187,16 @@ function(__qt_internal_collect_dependency_plugin_object_libraries target plugin_ __qt_internal_get_static_plugin_condition_genex("${plugin_target}" plugin_condition) foreach(plugin_object_library IN LISTS plugin_object_libraries) - list(APPEND plugin_objects - "$<${plugin_condition}:$>" + string(JOIN "" plugin_objects_genex + "$<" + "$," + "${plugin_condition}" + ">" + ":$" + ">" ) + list(APPEND plugin_objects "${plugin_objects_genex}") endforeach() endforeach() set(${out_var} "${plugin_objects}" PARENT_SCOPE) diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake index 81b98195ea9..539c6bd159f 100644 --- a/src/corelib/Qt6CoreMacros.cmake +++ b/src/corelib/Qt6CoreMacros.cmake @@ -1472,6 +1472,17 @@ function(__qt_internal_propagate_object_library target object_library) "$" ) + # Check if link options are propagated according to CMP0099 + # In user builds the _qt_cmp0099_policy_check is set to FALSE or $ + # depending on the used CMake version. + # See __qt_internal_check_cmp0099_available for details. + set(cmp0099_policy_check_property + "$" + ) + set(link_objects_using_link_options_condition + "$>" + ) + # Use TARGET_NAME to have the correct namespaced name in the exports. set(objects "$>") @@ -1482,6 +1493,7 @@ function(__qt_internal_propagate_object_library target object_library) "${not_finalizer_mode_condition}," "${not_static_condition}," "${platform_link_order_condition}," + "$," "${extra_conditions}" ">" ":${objects}>" @@ -1490,6 +1502,26 @@ function(__qt_internal_propagate_object_library target object_library) "${target_sources_genex}" ) + # Collect link conditions for the target_link_options call. + string(JOIN "" target_link_options_genex + "$<" + "$" + ":${objects}>" + ) + # target_link_options works well since CMake 3.17 which has policy CMP0099 set to NEW for the + # minimum required CMake version greated than or equal 3.17. The default is OLD. See + # https://cmake.org/cmake/help/git-master/policy/CMP0099.html for details. + # This provides yet another way of linking object libraries if user sets the policy to NEW + # before calling find_package(Qt...). + target_link_options(${target} INTERFACE + "${target_link_options_genex}" + ) + # Collect link conditions for the target_link_libraries call. string(JOIN "" target_link_libraries_genex "$<" diff --git a/tests/auto/cmake/test_QTBUG-63422/CMakeLists.txt b/tests/auto/cmake/test_QTBUG-63422/CMakeLists.txt index f2ac2a1ea23..d4effa63055 100644 --- a/tests/auto/cmake/test_QTBUG-63422/CMakeLists.txt +++ b/tests/auto/cmake/test_QTBUG-63422/CMakeLists.txt @@ -1,4 +1,8 @@ cmake_minimum_required(VERSION 3.14) +if(POLICY CMP0099) + cmake_policy(SET CMP0099 NEW) # Avoid CMP0099 related warnings. +endif() + project(test_dependent_modules) find_package(Qt6Widgets REQUIRED) 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 43363fa495e..a219d6938df 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 @@ -3,7 +3,6 @@ file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp" CONTENT "void dummy add_library(dummy STATIC "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp") target_link_libraries(dummy PRIVATE MockStaticResources1) - # Add the executable using qt_add_executable that needs to initialize the propagated resources. # Finalize it implicitly(since CMake version 3.19). if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19) @@ -35,11 +34,10 @@ target_link_libraries(test_static_resources_propagation_manual_finalize Qt::Core Qt::Test ) +qt_finalize_target(test_static_resources_propagation_manual_finalize) add_test(NAME test_static_resources_propagation_manual_finalize COMMAND test_static_resources_propagation_manual_finalize ) -qt_finalize_target(test_static_resources_propagation_manual_finalize) - # Add the executable using add_executable that needs to initialize the propagated resources. # Finalize it explicitly. @@ -98,3 +96,65 @@ if(NOT link_order_matters) ) endif() endif() + +# Add the executable using add_executable, expecting resources are propagated using +# target_link_options approach. The test is not applicable for qt_add_executable call since +# we use the CMP0099 policy NEW unless the actual version of CMake is lower than 3.17, that means +# target_link_options will always be preferable to finalizers. +if(POLICY CMP0099) + cmake_policy(PUSH) + + cmake_policy(SET CMP0099 OLD) + # When CMP0099 is set to OLD target_link_options doesn't propagate the linker options when + # linking static libraries with a PRIVATE visibility but we finalize it explicitly. This + # is a pure finalizer use case for platforms where link order matters. + add_executable(test_static_resources_propagation_cmp0099_old_finalize main.cpp) + set_target_properties(test_static_resources_propagation_cmp0099_old_finalize PROPERTIES + AUTOMOC TRUE + ) + target_link_libraries(test_static_resources_propagation_cmp0099_old_finalize + PRIVATE + dummy + Qt::Core + Qt::Test + ) + qt_finalize_target(test_static_resources_propagation_cmp0099_old_finalize) + add_test(NAME test_static_resources_propagation_cmp0099_old_finalize + COMMAND test_static_resources_propagation_cmp0099_old_finalize + ) + + # When CMP0099 is set to NEW target_link_options propagates the linker options when linking + # static libraries with a PRIVATE visibility. This is a pure target_link_options use case for + # platforms where link order matters. + cmake_policy(SET CMP0099 NEW) + add_executable(test_static_resources_propagation_cmp0099_new main.cpp) + set_target_properties(test_static_resources_propagation_cmp0099_new PROPERTIES + AUTOMOC TRUE + ) + target_link_libraries(test_static_resources_propagation_cmp0099_new + PRIVATE + dummy + Qt::Core + Qt::Test + ) + add_test(NAME test_static_resources_propagation_cmp0099_new + COMMAND test_static_resources_propagation_cmp0099_new + ) + + # Check if linking libraries using genex propagates resource objects when CMP0099 is enabled + add_executable(test_static_resources_propagation_cmp0099_new_genex main.cpp) + set_target_properties(test_static_resources_propagation_cmp0099_new_genex PROPERTIES + AUTOMOC TRUE + ) + target_link_libraries(test_static_resources_propagation_cmp0099_new_genex + PRIVATE + $<1:dummy> + Qt::Core + Qt::Test + ) + add_test(NAME test_static_resources_propagation_cmp0099_new_genex + COMMAND test_static_resources_propagation_cmp0099_new_genex + ) + + cmake_policy(POP) +endif()