diff options
author | Alexey Edelev <alexey.edelev@qt.io> | 2021-06-15 13:09:57 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-06-18 23:44:31 +0000 |
commit | 2f8572dd3b5781b1e4c4d627ae74172ac8ac3c19 (patch) | |
tree | 857e3a90da6b88c1a455a75e56e290abca215c09 | |
parent | 30026fa0eed914065508a77ce8cdad9593afcf7c (diff) |
Move the linking logic of the object libraries to a common function
The linking logic of object libraries should be reusable outside of the
resource context. This introduces a
__qt_internal_propagate_object_library function that prepares all the
necessary genexes to link and propagate the object library to the
end-point executable.
Rename resource object finalizer API to make the naming more generic
to object libraries of any kind.
Amends 5fb99e3860eb43f4bacacec7f4a4626cb0159b14
Task-number: QTBUG-93002
Task-number: QTBUG-94528
Change-Id: I69d0f34c0dadbd67232de91035aaa53af93d1fa1
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
(cherry picked from commit 3329212815777e33dfb4697b748d10927d73f44c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | cmake/QtPublicTargetHelpers.cmake | 78 | ||||
-rw-r--r-- | src/corelib/Qt6CoreMacros.cmake | 188 | ||||
-rw-r--r-- | tests/auto/cmake/test_static_resources/test_static_resources_propagation/CMakeLists.txt | 2 |
3 files changed, 154 insertions, 114 deletions
diff --git a/cmake/QtPublicTargetHelpers.cmake b/cmake/QtPublicTargetHelpers.cmake index be76efd835..94bda88d66 100644 --- a/cmake/QtPublicTargetHelpers.cmake +++ b/cmake/QtPublicTargetHelpers.cmake @@ -87,8 +87,8 @@ function(__qt_internal_check_link_order_matters) endif() 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 +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 # line. # So circular dependencies between static libraries and object files are resolved and no need @@ -98,68 +98,68 @@ function(__qt_internal_process_dependency_resource_objects target) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21) return() endif() - get_target_property(processed ${target} _qt_resource_object_finalizers_processed) + get_target_property(processed ${target} _qt_object_libraries_finalizer_processed) if(processed) return() endif() - set_target_properties(${target} PROPERTIES _qt_resource_object_finalizers_processed TRUE) + set_target_properties(${target} PROPERTIES _qt_object_libraries_finalizer_processed TRUE) __qt_internal_check_finalizer_mode(${target} use_finalizer_mode - resource_objects + object_libraries ) if(NOT use_finalizer_mode) return() endif() - __qt_internal_collect_dependency_resource_objects(${target} resource_objects) - target_sources(${target} PRIVATE "${resource_objects}") + __qt_internal_collect_dependency_object_libraries(${target} objects) + target_sources(${target} PRIVATE "${objects}") endfunction() -function(__qt_internal_collect_dependency_resource_objects target out_var) - set_property(GLOBAL PROPERTY _qt_resource_processed_targets "") +function(__qt_internal_collect_dependency_object_libraries target out_var) + set_property(GLOBAL PROPERTY _qt_processed_object_libraries "") - __qt_internal_collect_resource_objects_recursively(resource_targets ${target} ${target}) + __qt_internal_collect_object_libraries_recursively(object_libraries ${target} ${target}) - # Collect resource objects of plugins and plugin dependencies. + # Collect object libraries of plugins and plugin dependencies. __qt_internal_collect_plugin_targets_from_dependencies(${target} plugin_targets) - __qt_internal_collect_dependency_plugin_resource_objects(${target} + __qt_internal_collect_dependency_plugin_object_libraries(${target} "${plugin_targets}" - plugin_resource_objects + plugin_objects ) - set_property(GLOBAL PROPERTY _qt_resource_processed_targets "") + set_property(GLOBAL PROPERTY _qt_processed_object_libraries "") - list(REMOVE_DUPLICATES resource_targets) - set(resource_objects "") - foreach(dep IN LISTS resource_targets) - list(PREPEND resource_objects "$<TARGET_OBJECTS:${dep}>") + list(REMOVE_DUPLICATES object_libraries) + set(objects "") + foreach(dep IN LISTS object_libraries) + list(PREPEND objects "$<TARGET_OBJECTS:${dep}>") endforeach() - set(${out_var} "${plugin_resource_objects};${resource_objects}" PARENT_SCOPE) + set(${out_var} "${plugin_objects};${objects}" PARENT_SCOPE) endfunction() -function(__qt_internal_collect_dependency_plugin_resource_objects target plugin_targets out_var) - set(plugin_resource_objects "") +function(__qt_internal_collect_dependency_plugin_object_libraries target plugin_targets out_var) + set(plugin_objects "") foreach(plugin_target IN LISTS plugin_targets) - __qt_internal_collect_resource_objects_recursively(plugin_resource_targets + __qt_internal_collect_object_libraries_recursively(plugin_object_libraries "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}" ${target} ) __qt_internal_get_static_plugin_condition_genex("${plugin_target}" plugin_condition) - foreach(plugin_resource_target IN LISTS plugin_resource_targets) - list(APPEND plugin_resource_objects - "$<${plugin_condition}:$<TARGET_OBJECTS:${plugin_resource_target}>>" + foreach(plugin_object_library IN LISTS plugin_object_libraries) + list(APPEND plugin_objects + "$<${plugin_condition}:$<TARGET_OBJECTS:${plugin_object_library}>>" ) endforeach() endforeach() - set(${out_var} "${plugin_resource_objects}" PARENT_SCOPE) + set(${out_var} "${plugin_objects}" PARENT_SCOPE) endfunction() -function(__qt_internal_collect_resource_objects_recursively out_var target initial_target) - get_property(resource_processed_targets GLOBAL PROPERTY _qt_resource_processed_targets) +function(__qt_internal_collect_object_libraries_recursively out_var target initial_target) + get_property(processed_object_libraries GLOBAL PROPERTY _qt_processed_object_libraries) set(interface_libs "") set(libs "") @@ -171,7 +171,7 @@ function(__qt_internal_collect_resource_objects_recursively out_var target initi get_target_property(libs ${target} LINK_LIBRARIES) endif() - set(resource_targets "") + set(object_libraries "") foreach(lib IN LISTS libs interface_libs) if(TARGET ${lib}) get_target_property(aliased_target ${lib} ALIASED_TARGET) @@ -179,26 +179,28 @@ function(__qt_internal_collect_resource_objects_recursively out_var target initi set(lib ${aliased_target}) endif() - if(${lib} IN_LIST resource_processed_targets) + if(${lib} IN_LIST processed_object_libraries) continue() else() - list(APPEND resource_processed_targets ${lib}) - set_property(GLOBAL APPEND PROPERTY _qt_resource_processed_targets ${lib}) + list(APPEND processed_object_libraries ${lib}) + set_property(GLOBAL APPEND PROPERTY _qt_processed_object_libraries ${lib}) endif() - get_target_property(is_qt_resource ${lib} _is_qt_resource_target) - if(is_qt_resource) - list(APPEND resource_targets ${lib}) + get_target_property(is_qt_propagated_object_library ${lib} + _is_qt_propagated_object_library + ) + if(is_qt_propagated_object_library) + list(APPEND object_libraries ${lib}) else() - __qt_internal_collect_resource_objects_recursively(next_level_resources + __qt_internal_collect_object_libraries_recursively(next_level_object_libraries ${lib} ${initial_target} ) - list(APPEND resource_targets ${next_level_resources}) + list(APPEND object_libraries ${next_level_object_libraries}) endif() endif() endforeach() - set(${out_var} "${resource_targets}" PARENT_SCOPE) + set(${out_var} "${object_libraries}" PARENT_SCOPE) endfunction() function(__qt_internal_promote_target_to_global target) diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake index 3636ddecd9..88bf5052bf 100644 --- a/src/corelib/Qt6CoreMacros.cmake +++ b/src/corelib/Qt6CoreMacros.cmake @@ -596,7 +596,7 @@ function(_qt_internal_finalize_executable target) get_target_property(is_immediately_finalized "${target}" _qt_is_immediately_finalized) if(NOT is_immediately_finalized) __qt_internal_apply_plugin_imports_finalizer_mode("${target}") - __qt_internal_process_dependency_resource_objects("${target}") + __qt_internal_process_dependency_object_libraries("${target}") endif() set_target_properties(${target} PROPERTIES _qt_executable_is_finalized TRUE) @@ -914,13 +914,13 @@ endif() # It makes sense to manually disable the finalizer of the resource object if you are using # linkers other than ld, since the dependencies between resource objects and static libraries # are resolved correctly by them. -function(qt6_enable_resource_objects_finalizer_mode target enabled) - __qt_internal_enable_finalizer_mode(${target} resource_objects ${enabled}) +function(qt6_enable_object_libraries_finalizer_mode target enabled) + __qt_internal_enable_finalizer_mode(${target} object_libraries ${enabled}) endfunction() if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS) - function(qt_enable_resource_objects_finalizer_mode) - qt6_enable_resource_objects_finalizer_mode(${ARGV}) + function(qt_enable_object_libraries_finalizer_mode) + qt6_enable_object_libraries_finalizer_mode(${ARGV}) endfunction() endif() @@ -1408,6 +1408,107 @@ function(__qt_get_relative_resource_path_for_file output_alias file) set(${output_alias} ${alias} PARENT_SCOPE) endfunction() +# Performs linking and propagation of the object library via the target's usage requirements. +# Arguments: +# NO_LINK_OBJECT_LIBRARY_REQUIREMENTS_TO_TARGET skip linking of ${object_library} to ${target}, only +# propagate $<TARGET_OBJECTS:${object_library}> by linking it to ${target}. It's useful in case +# if ${object_library} depends on the ${target}. E.g. resource libraries depend on the Core +# library so linking them back to Core will cause a CMake error. +# +# EXTRA_CONDITIONS object library specific conditions to be checked before link the object library +# to the end-point executable. +function(__qt_internal_propagate_object_library target object_library) + set(options NO_LINK_OBJECT_LIBRARY_REQUIREMENTS_TO_TARGET) + set(single_args "") + set(multi_args EXTRA_CONDITIONS) + cmake_parse_arguments(arg "${options}" "${single_args}" "${multi_args}" ${ARGN}) + + target_link_libraries(${object_library} PRIVATE ${QT_CMAKE_EXPORT_NAMESPACE}::Platform) + _qt_internal_copy_dependency_properties(${object_library} ${target} PRIVATE_ONLY) + + # After internal discussion we decided to not rely on the linker order that CMake + # offers, until CMake provides the guaranteed linking order that suites our needs in a + # future CMake version. + # All object libraries mark themselves with the _is_qt_propagated_object_library property. + # Using a finalizer approach we walk through the target dependencies and look for libraries + # using the _is_qt_propagated_object_library property. Then, objects of the collected libraries + # are moved to the beginnig of the linker line using target_sources. + # + # Note: target_link_libraries works well with linkers other than ld. If user didn't enforce + # a finalizer we rely on linker to resolve circular dependencies between objects and static + # libraries. + set_property(TARGET ${object_library} PROPERTY _is_qt_propagated_object_library TRUE) + set_property(TARGET ${object_library} APPEND PROPERTY + EXPORT_PROPERTIES _is_qt_propagated_object_library + ) + + # Keep the implicit linking if finalizers are not used. + set(not_finalizer_mode_condition + "$<NOT:$<BOOL:$<TARGET_PROPERTY:_qt_object_libraries_finalizer_mode>>>" + ) + + # Collect object library specific conditions. + if(arg_EXTRA_CONDITIONS) + list(JOIN arg_EXTRA_CONDITIONS "," extra_conditions) + else() + set(extra_conditions "$<BOOL:TRUE>") + endif() + + # Do not litter the static libraries + set(not_static_condition + "$<NOT:$<STREQUAL:$<TARGET_PROPERTY:TYPE>,STATIC_LIBRARY>>" + ) + + # Check if link order matters for the Platform. + set(platform_link_order_property + "$<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::Platform,_qt_link_order_matters>" + ) + set(platform_link_order_condition + "$<BOOL:${platform_link_order_property}>" + ) + + # Use TARGET_NAME to have the correct namespaced name in the exports. + set(objects "$<TARGET_OBJECTS:$<TARGET_NAME:${object_library}>>") + + # Collect link conditions for the target_sources call. + string(JOIN "" target_sources_genex + "$<" + "$<AND:" + "${not_finalizer_mode_condition}," + "${not_static_condition}," + "${platform_link_order_condition}," + "${extra_conditions}" + ">" + ":${objects}>" + ) + target_sources(${target} INTERFACE + "${target_sources_genex}" + ) + + # Collect link conditions for the target_link_libraries call. + string(JOIN "" target_link_libraries_genex + "$<" + "$<AND:" + "${not_finalizer_mode_condition}," + "${not_static_condition}," + "$<NOT:${platform_link_order_condition}>," + "${extra_conditions}" + ">" + ":${objects}>" + ) + target_link_libraries(${target} INTERFACE + "${target_link_libraries_genex}" + ) + + if(NOT arg_NO_LINK_OBJECT_LIBRARY_REQUIREMENTS_TO_TARGET) + # It's necessary to link the object library target, since we want to pass the object library + # dependencies to the 'target'. Interface linking doesn't add the objects of the library to + # the end-point linker line but propagates all the dependencies of the object_library added + # before or AFTER the line below. + target_link_libraries(${target} INTERFACE ${object_library}) + endif() +endfunction() + function(__qt_propagate_generated_resource target resource_name generated_source_code output_generated_target) get_target_property(type ${target} TYPE) if(type STREQUAL STATIC_LIBRARY) @@ -1424,13 +1525,10 @@ function(__qt_propagate_generated_resource target resource_name generated_source "$<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::Core,INTERFACE_COMPILE_DEFINITIONS>" ) - target_link_libraries(${resource_target} PRIVATE ${QT_CMAKE_EXPORT_NAMESPACE}::Platform) - _qt_internal_copy_dependency_properties(${resource_target} ${target} PRIVATE_ONLY) - # Special handling is required for the Core library resources. The linking of the Core # library to the resources adds a circular dependency. This leads to the wrong - # objects/library order in the linker command line, since the Core library target is resolved - # first. + # objects/library order in the linker command line, since the Core library target is + # resolved first. if(NOT target STREQUAL "Core") target_link_libraries(${resource_target} INTERFACE ${QT_CMAKE_EXPORT_NAMESPACE}::Core) endif() @@ -1447,73 +1545,13 @@ function(__qt_propagate_generated_resource target resource_name generated_source set_property(TARGET ${resource_target} APPEND PROPERTY _qt_resource_generated_cpp_relative_path "${generated_cpp_file_relative_path}") - # After internal discussion we decided to not rely on the linker order that CMake - # offers, until CMake provides the guaranteed linking order that suites our needs in a - # future CMake version. - # All resource object libraries mark themselves with the _is_qt_resource_target property. - # Using a finalizer approach we walk through the target dependencies and look for - # resource libraries using the _is_qt_resource_target property. Then, resource objects of - # the collected libraries are moved to the beginnig of the linker line using target_sources. - # - # target_link_libraries works well with linkers other than ld. If user didn't enforce - # a finalizer we rely on linker to resolve circular dependencies between resource - # objects and static libraries. - set_property(TARGET ${resource_target} PROPERTY _is_qt_resource_target TRUE) - set_property(TARGET ${resource_target} APPEND PROPERTY - EXPORT_PROPERTIES _is_qt_resource_target - ) - - # Keep the implicit linking if finalizers are not used. - set(not_finalizer_mode_condition - "$<NOT:$<BOOL:$<TARGET_PROPERTY:_qt_resource_objects_finalizer_mode>>>" - ) - # Do not litter the static libraries - set(not_static_condition - "$<NOT:$<STREQUAL:$<TARGET_PROPERTY:TYPE>,STATIC_LIBRARY>>" - ) - set(resource_objects "$<TARGET_OBJECTS:$<TARGET_NAME:${resource_target}>>") - - set(platform_link_order_property - "$<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::Platform,_qt_link_order_matters>" - ) - set(platform_link_order_condition - "$<BOOL:${platform_link_order_property}>" - ) - - string(JOIN "" target_sources_genex - "$<" - "$<AND:" - "${not_finalizer_mode_condition}," - "${not_static_condition}," - "${platform_link_order_condition}" - ">" - ":${resource_objects}>" - ) - target_sources(${target} INTERFACE - "${target_sources_genex}" - ) - - string(JOIN "" target_link_libraries_genex - "$<" - "$<AND:" - "${not_finalizer_mode_condition}," - "${not_static_condition}," - "$<NOT:${platform_link_order_condition}>" - ">" - ":${resource_objects}>" - ) - target_link_libraries(${target} INTERFACE - "${target_link_libraries_genex}" + if(target STREQUAL "Core") + set(skip_direct_linking NO_LINK_OBJECT_LIBRARY_REQUIREMENTS_TO_TARGET) + endif() + __qt_internal_propagate_object_library(${target} ${resource_target} + ${skip_direct_linking} ) - if(NOT target STREQUAL "Core") - # It's necessary to link the object library target, since we want to pass - # the object library dependencies to the 'target'. Interface linking doesn't - # add the objects of the resource library to the end-point linker line - # but propagates all the dependencies of the resource_target added before - # or AFTER the line below. - target_link_libraries(${target} INTERFACE ${resource_target}) - endif() set(${output_generated_target} "${resource_target}" PARENT_SCOPE) else() set(${output_generated_target} "" PARENT_SCOPE) 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 58a7c4147a..43363fa495 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 @@ -81,7 +81,7 @@ if(NOT link_order_matters) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19) qt_add_executable(test_static_resources_propagation_not_finalize main.cpp) - qt6_enable_resource_objects_finalizer_mode( + qt6_enable_object_libraries_finalizer_mode( test_static_resources_propagation_not_finalize FALSE ) set_target_properties(test_static_resources_propagation_not_finalize PROPERTIES |