From 2f8572dd3b5781b1e4c4d627ae74172ac8ac3c19 Mon Sep 17 00:00:00 2001 From: Alexey Edelev Date: Tue, 15 Jun 2021 13:09:57 +0200 Subject: 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 (cherry picked from commit 3329212815777e33dfb4697b748d10927d73f44c) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/Qt6CoreMacros.cmake | 188 ++++++++++++++++++++++++---------------- 1 file changed, 113 insertions(+), 75 deletions(-) (limited to 'src') 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 $ 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 + "$>>" + ) + + # Collect object library specific conditions. + if(arg_EXTRA_CONDITIONS) + list(JOIN arg_EXTRA_CONDITIONS "," extra_conditions) + else() + set(extra_conditions "$") + endif() + + # Do not litter the static libraries + set(not_static_condition + "$,STATIC_LIBRARY>>" + ) + + # Check if link order matters for the Platform. + set(platform_link_order_property + "$" + ) + set(platform_link_order_condition + "$" + ) + + # Use TARGET_NAME to have the correct namespaced name in the exports. + set(objects "$>") + + # Collect link conditions for the target_sources call. + string(JOIN "" target_sources_genex + "$<" + "$" + ":${objects}>" + ) + target_sources(${target} INTERFACE + "${target_sources_genex}" + ) + + # Collect link conditions for the target_link_libraries call. + string(JOIN "" target_link_libraries_genex + "$<" + "$," + "${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_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 - "$>>" - ) - # Do not litter the static libraries - set(not_static_condition - "$,STATIC_LIBRARY>>" - ) - set(resource_objects "$>") - - set(platform_link_order_property - "$" - ) - set(platform_link_order_condition - "$" - ) - - 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(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) -- cgit v1.2.3