summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Edelev <alexey.edelev@qt.io>2021-06-29 18:00:39 +0200
committerAlexey Edelev <alexey.edelev@qt.io>2021-07-02 15:17:06 +0200
commite80b0107952272aa3382a84aeb6d11b6047d775e (patch)
treeff9d69552133287129092298367eaf8d681e8660
parentc72b7b8e5e530fbd03b704380940f5fa86e5341d (diff)
Use target_link_options to propagate object libraries
target_link_options are placed by CMake at the beginning of a linker line. This gives us an opportunity to use the function to propagate object libraries. This change adds one more check in the root Config.cmake file. If CMP0099 policy is enabled, CMake enables propagating of the linking options when linking two static libraries using the PRIVATE linking visibility, so we can rely on the correct linking order and expect object libraries to be propagated. Note that on the platforms where cmake version is higher than 3.16 Qt uses CMP0099 NEW in functions like qt_add_executable. This means that at the moment of creating an executable target the TARGET_POLICY genex will also be NEW, so we do not take into the account the user defined CMP0099. If the CMP0099 policy is not available for a certain CMake version we skip the TARGET_POLICY check and simply disable propagation of the object libraries using target_link_options for both user and Qt libraries. This is applicable for the CMake versions 3.16 and less. Linking approaches have the following priorities(from higher to lower) after this change: - target_link_libraries - works if link order matters not or CMake version greater equal 3.21. - target_link_options - works if CMP0099 is set to NEW by user or if the CMake version is greater than or equal to 3.17 and an executable is created using Qt functions. - object library finalizer - works if CMake version is greater equal 3.19 or qt6_finalize_target is called explicitly. - target_sources - is used when all the other approaches could not be used. Amends a1fd4f51ada82854f35654158a334454e760a9f7 Amends 3329212815777e33dfb4697b748d10927d73f44c Pick-to: 6.2 Change-Id: I14f88caeb04e357191c840abeab89b03e210b796 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
-rw-r--r--cmake/QtBuildInternals/QtBuildInternalsConfig.cmake19
-rw-r--r--cmake/QtConfig.cmake.in5
-rw-r--r--cmake/QtPublicTargetHelpers.cmake46
-rw-r--r--src/corelib/Qt6CoreMacros.cmake32
-rw-r--r--tests/auto/cmake/test_QTBUG-63422/CMakeLists.txt4
-rw-r--r--tests/auto/cmake/test_static_resources/test_static_resources_propagation/CMakeLists.txt66
6 files changed, 165 insertions, 7 deletions
diff --git a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake
index 2547282dca..8fa0e69c3e 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 cc3b2d7fce..92e47a04a0 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 a116d2dd5d..b84a874880 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} "$<BOOL:$<TARGET_POLICY:CMP0099>>" PARENT_SCOPE)
+ else()
+ set(${result} "$<BOOL:FALSE>" 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 "$<TARGET_OBJECTS:${dep}>")
+ list(PREPEND objects "$<$<NOT:${cmp0099_check}>:$<TARGET_OBJECTS:${dep}>>")
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}:$<TARGET_OBJECTS:${plugin_object_library}>>"
+ string(JOIN "" plugin_objects_genex
+ "$<"
+ "$<AND:"
+ "$<NOT:${cmp0099_check}>,"
+ "${plugin_condition}"
+ ">"
+ ":$<TARGET_OBJECTS:${plugin_object_library}>"
+ ">"
)
+ 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 81b98195ea..539c6bd159 100644
--- a/src/corelib/Qt6CoreMacros.cmake
+++ b/src/corelib/Qt6CoreMacros.cmake
@@ -1472,6 +1472,17 @@ function(__qt_internal_propagate_object_library target object_library)
"$<BOOL:${platform_link_order_property}>"
)
+ # Check if link options are propagated according to CMP0099
+ # In user builds the _qt_cmp0099_policy_check is set to FALSE or $<TARGET_POLICY:CMP0099>
+ # depending on the used CMake version.
+ # See __qt_internal_check_cmp0099_available for details.
+ set(cmp0099_policy_check_property
+ "$<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::Platform,_qt_cmp0099_policy_check>"
+ )
+ set(link_objects_using_link_options_condition
+ "$<BOOL:$<GENEX_EVAL:${cmp0099_policy_check_property}>>"
+ )
+
# Use TARGET_NAME to have the correct namespaced name in the exports.
set(objects "$<TARGET_OBJECTS:$<TARGET_NAME:${object_library}>>")
@@ -1482,6 +1493,7 @@ function(__qt_internal_propagate_object_library target object_library)
"${not_finalizer_mode_condition},"
"${not_static_condition},"
"${platform_link_order_condition},"
+ "$<NOT:${link_objects_using_link_options_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
+ "$<"
+ "$<AND:"
+ "${not_static_condition},"
+ "${platform_link_order_condition},"
+ "${link_objects_using_link_options_condition},"
+ "${extra_conditions}"
+ ">"
+ ":${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 f2ac2a1ea2..d4effa6305 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 43363fa495..a219d6938d 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()