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

Pick-to: 6.2
Task-number: QTBUG-93002
Task-number: QTBUG-94528
Change-Id: I69d0f34c0dadbd67232de91035aaa53af93d1fa1
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
This commit is contained in:
Alexey Edelev 2021-06-15 13:09:57 +02:00
parent df31696321
commit 3329212815
3 changed files with 155 additions and 115 deletions

View File

@ -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)

View File

@ -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(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})
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}
)
set(${output_generated_target} "${resource_target}" PARENT_SCOPE)
else()
set(${output_generated_target} "" PARENT_SCOPE)

View File

@ -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