CMake: Make qt_internal_walk_libs available in public projects
Needed for the upcoming static plugin mechanism, where we have to extract the list of Qt module dependencies of a target and then extract the plugins associated with those modules. To do that we need to recursively collect the dependencies of a given target. Rename the moved functions to contain the __qt_internal prefix. Also rename the existing QtPublicTargetsHelpers.cmake into QtPlatformTargetHelpers.cmake to avoid confusion with the newly introduced QtPublicTargetHelpers.cmake. Task-number: QTBUG-92933 Change-Id: I48b5b6a8718a3424f59ca60f11fc9e97a809765d Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
parent
b70a4da4f7
commit
471ff20f33
@ -134,7 +134,7 @@ target_include_directories(GlobalConfigPrivate INTERFACE
|
||||
)
|
||||
add_library(Qt::GlobalConfigPrivate ALIAS GlobalConfigPrivate)
|
||||
|
||||
include(QtPublicTargetsHelpers)
|
||||
include(QtPlatformTargetHelpers)
|
||||
qt_internal_setup_public_platform_target()
|
||||
|
||||
# defines PlatformCommonInternal PlatformModuleInternal PlatformPluginInternal PlatformToolInternal
|
||||
@ -214,7 +214,7 @@ qt_copy_or_install(FILES
|
||||
cmake/QtPrecompiledHeadersHelpers.cmake
|
||||
cmake/QtPriHelpers.cmake
|
||||
cmake/QtPrlHelpers.cmake
|
||||
cmake/QtPublicTargetsHelpers.cmake
|
||||
cmake/QtPlatformTargetHelpers.cmake
|
||||
cmake/QtProcessConfigureArgs.cmake
|
||||
cmake/QtQmakeHelpers.cmake
|
||||
cmake/QtResourceHelpers.cmake
|
||||
@ -245,6 +245,8 @@ set(__public_cmake_helpers
|
||||
cmake/QtFeature.cmake
|
||||
cmake/QtFeatureCommon.cmake
|
||||
cmake/QtPublicPluginHelpers.cmake
|
||||
cmake/QtPublicTargetHelpers.cmake
|
||||
cmake/QtPublicWalkLibsHelpers.cmake
|
||||
)
|
||||
|
||||
qt_copy_or_install(FILES ${__public_cmake_helpers} DESTINATION "${__GlobalConfig_install_dir}")
|
||||
|
@ -547,6 +547,8 @@ endif()
|
||||
|
||||
# Helpers that are available in public projects and while building Qt itself.
|
||||
include(QtPublicPluginHelpers)
|
||||
include(QtPublicTargetHelpers)
|
||||
include(QtPublicWalkLibsHelpers)
|
||||
|
||||
|
||||
# TODO: This block provides support for old variables. It should be removed once
|
||||
|
@ -56,6 +56,8 @@ file(TO_CMAKE_PATH "$ENV{QT_ADDITIONAL_PACKAGES_PREFIX_PATH}" _qt_additional_pac
|
||||
# Public helpers available to all Qt packages.
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/QtFeature.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/QtPublicPluginHelpers.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/QtPublicTargetHelpers.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/QtPublicWalkLibsHelpers.cmake")
|
||||
|
||||
# Find required dependencies, if any.
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
@ -7,10 +7,10 @@
|
||||
# Only works if called from qt_find_package(), because the promotion needs to happen in the same
|
||||
# directory scope where the imported target is first created.
|
||||
#
|
||||
# Uses qt_internal_walk_libs.
|
||||
# Uses __qt_internal_walk_libs.
|
||||
function(qt_find_package_promote_targets_to_global_scope target)
|
||||
qt_internal_walk_libs("${target}" _discarded_out_var _discarded_out_var_2
|
||||
"qt_find_package_targets_dict" "promote_global")
|
||||
__qt_internal_walk_libs("${target}" _discarded_out_var _discarded_out_var_2
|
||||
"qt_find_package_targets_dict" "promote_global")
|
||||
endfunction()
|
||||
|
||||
macro(qt_find_package)
|
||||
|
@ -36,7 +36,7 @@ macro(qt_collect_third_party_deps target)
|
||||
endif()
|
||||
|
||||
# Strip any directory scope tokens.
|
||||
qt_internal_strip_target_directory_scope_token("${dep}" dep)
|
||||
__qt_internal_strip_target_directory_scope_token("${dep}" dep)
|
||||
if(TARGET ${dep})
|
||||
list(FIND third_party_deps_seen ${dep} dep_seen)
|
||||
|
||||
|
@ -1,250 +1,15 @@
|
||||
# Add libraries to variable ${out_libs_var} in a way that duplicates
|
||||
# are added at the end. This ensures the library order needed for the
|
||||
# linker.
|
||||
function(qt_merge_libs out_libs_var)
|
||||
foreach(dep ${ARGN})
|
||||
list(REMOVE_ITEM ${out_libs_var} ${dep})
|
||||
list(APPEND ${out_libs_var} ${dep})
|
||||
endforeach()
|
||||
set(${out_libs_var} ${${out_libs_var}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Collects the library dependencies of a target.
|
||||
# As well as rcc object file dependencies.
|
||||
# This takes into account transitive usage requirements.
|
||||
function(qt_collect_libs target libs_out_var rcc_objects_out_var)
|
||||
qt_internal_walk_libs("${target}" "${libs_out_var}"
|
||||
"${rcc_objects_out_var}" "qt_collect_libs_dict" "collect_libs")
|
||||
__qt_internal_walk_libs("${target}" "${libs_out_var}"
|
||||
"${rcc_objects_out_var}" "qt_collect_libs_dict" "collect_libs")
|
||||
set("${libs_out_var}" "${${libs_out_var}}" PARENT_SCOPE)
|
||||
|
||||
set(${rcc_objects_out_var} "${${rcc_objects_out_var}}" PARENT_SCOPE)
|
||||
|
||||
endfunction()
|
||||
|
||||
# Extracts value from per-target dict key and assigns it to out_var.
|
||||
# Assumes dict_name to be an existing INTERFACE target.
|
||||
function(qt_internal_get_dict_key_values out_var target_infix dict_name dict_key)
|
||||
get_target_property(values "${dict_name}" "INTERFACE_${target_infix}_${dict_key}")
|
||||
set(${out_var} "${values}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Assigns 'values' to per-target dict key, including for aliases of the target.
|
||||
# Assumes dict_name to be an existing INTERFACE target.
|
||||
function(qt_internal_memoize_values_in_dict target dict_name dict_key values)
|
||||
# Memoize the computed values for the target as well as its aliases.
|
||||
#
|
||||
# Aka assigns the contents of ${values} to INTERFACE_Core, INTERFACE_Qt::Core,
|
||||
# INTERFACE_Qt6::Core.
|
||||
#
|
||||
# Yes, i know it's crazy that target names are legal property names.
|
||||
#
|
||||
# Assigning for library aliases is needed to avoid multiple recomputation of values.
|
||||
# Scenario in the context of qt_internal_walk_libs:
|
||||
# 'values' are computed for Core target and memoized to INTERFACE_Core.
|
||||
# When processing Gui, it depends on Qt::Core, but there are no values for INTERFACE_Qt::Core.
|
||||
set_target_properties(${dict_name} PROPERTIES INTERFACE_${target}_${dict_key} "${values}")
|
||||
|
||||
get_target_property(versionless_alias "${target}" "_qt_versionless_alias")
|
||||
if(versionless_alias)
|
||||
qt_internal_get_dict_key_values(
|
||||
versionless_values "${versionless_alias}" "${dict_name}" "${dict_key}")
|
||||
if(versionless_values MATCHES "-NOTFOUND$")
|
||||
set_target_properties(${dict_name}
|
||||
PROPERTIES INTERFACE_${versionless_alias}_${dict_key} "${values}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
get_target_property(versionfull_alias "${target}" "_qt_versionfull_alias")
|
||||
if(versionfull_alias)
|
||||
qt_internal_get_dict_key_values(
|
||||
versionfull_values "${versionfull_alias}" "${dict_name}" "${dict_key}")
|
||||
if(versionfull_values MATCHES "-NOTFOUND$")
|
||||
set_target_properties(${dict_name}
|
||||
PROPERTIES INTERFACE_${versionfull_alias}_${dict_key} "${values}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Walks a target's link libraries recursively, and performs some actions (poor man's polypmorphism)
|
||||
#
|
||||
# out_var is the name of the variable where the result will be assigned. The result is a list of
|
||||
# libraries, mostly in generator expression form.
|
||||
# rcc_objects_out_var is the name of the variable where the collected rcc object files will be
|
||||
# assigned (for the initial target and its dependencies)
|
||||
# dict_name is used for caching the results, and preventing the same target from being processed
|
||||
# twice
|
||||
# operation is a string to tell the function what additional behaviors to execute.
|
||||
function(qt_internal_walk_libs
|
||||
target out_var rcc_objects_out_var dict_name operation)
|
||||
set(collected ${ARGN})
|
||||
if(target IN_LIST collected)
|
||||
return()
|
||||
endif()
|
||||
list(APPEND collected ${target})
|
||||
|
||||
if(target STREQUAL "${QT_CMAKE_EXPORT_NAMESPACE}::EntryPoint")
|
||||
# We can't (and don't need to) process EntryPoint because it brings in $<TARGET_PROPERTY:prop>
|
||||
# genexes which get replaced with $<TARGET_PROPERTY:EntryPoint,prop> genexes in the code below
|
||||
# and that causes 'INTERFACE_LIBRARY targets may only have whitelisted properties.' errors
|
||||
# with CMake versions equal to or lower than 3.18. These errors are super unintuitive to
|
||||
# debug because there's no mention that it's happening during a file(GENERATE) call.
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET ${dict_name})
|
||||
add_library(${dict_name} INTERFACE IMPORTED GLOBAL)
|
||||
endif()
|
||||
qt_internal_get_dict_key_values(libs "${target}" "${dict_name}" "libs")
|
||||
qt_internal_get_dict_key_values(rcc_objects "${target}" "${dict_name}" "rcc_objects")
|
||||
|
||||
if(libs MATCHES "-NOTFOUND$")
|
||||
unset(libs)
|
||||
unset(rcc_objects)
|
||||
get_target_property(target_libs ${target} INTERFACE_LINK_LIBRARIES)
|
||||
if(NOT target_libs)
|
||||
unset(target_libs)
|
||||
endif()
|
||||
get_target_property(target_type ${target} TYPE)
|
||||
if(target_type STREQUAL "STATIC_LIBRARY")
|
||||
get_target_property(link_libs ${target} LINK_LIBRARIES)
|
||||
if(link_libs)
|
||||
list(APPEND target_libs ${link_libs})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Need to record the rcc object file info not only for dependencies, but also for
|
||||
# the current target too. Otherwise the saved information is incomplete for prl static
|
||||
# build purposes.
|
||||
get_target_property(main_target_rcc_objects ${target} _qt_rcc_objects)
|
||||
if(main_target_rcc_objects)
|
||||
qt_merge_libs(rcc_objects ${main_target_rcc_objects})
|
||||
endif()
|
||||
|
||||
foreach(lib ${target_libs})
|
||||
# Cannot use $<TARGET_POLICY:...> in add_custom_command.
|
||||
# Check the policy now, and replace the generator expression with the value.
|
||||
while(lib MATCHES "\\$<TARGET_POLICY:([^>]+)>")
|
||||
cmake_policy(GET ${CMAKE_MATCH_1} value)
|
||||
if(value STREQUAL "NEW")
|
||||
set(value "TRUE")
|
||||
else()
|
||||
set(value "FALSE")
|
||||
endif()
|
||||
string(REPLACE "${CMAKE_MATCH_0}" "${value}" lib "${lib}")
|
||||
endwhile()
|
||||
|
||||
# Fix up $<TARGET_PROPERTY:FOO> expressions that refer to the "current" target.
|
||||
# Those cannot be used with add_custom_command.
|
||||
while(lib MATCHES "\\$<TARGET_PROPERTY:([^,>]+)>")
|
||||
string(REPLACE "${CMAKE_MATCH_0}" "$<TARGET_PROPERTY:${target},${CMAKE_MATCH_1}>"
|
||||
lib "${lib}")
|
||||
endwhile()
|
||||
|
||||
# Skip static plugins.
|
||||
set(_is_plugin_marker_genex "\\$<BOOL:QT_IS_PLUGIN_GENEX>")
|
||||
if(lib MATCHES "${_is_plugin_marker_genex}")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# Strip any directory scope tokens.
|
||||
qt_internal_strip_target_directory_scope_token("${lib}" lib)
|
||||
|
||||
if(lib MATCHES "^\\$<TARGET_OBJECTS:")
|
||||
# Skip object files.
|
||||
continue()
|
||||
elseif(lib MATCHES "^\\$<LINK_ONLY:(.*)>$")
|
||||
set(lib_target ${CMAKE_MATCH_1})
|
||||
else()
|
||||
set(lib_target ${lib})
|
||||
endif()
|
||||
|
||||
# Skip CMAKE_DIRECTORY_ID_SEP. If a target_link_libraries is applied to a target
|
||||
# that was defined in a different scope, CMake appends and prepends a special directory
|
||||
# id separator. Filter those out.
|
||||
if(lib_target MATCHES "^::@")
|
||||
continue()
|
||||
elseif(TARGET ${lib_target})
|
||||
if ("${lib_target}" MATCHES "^Qt::(.*)")
|
||||
# If both, Qt::Foo and Foo targets exist, prefer the target name without
|
||||
# namespace. Which one is preferred doesn't really matter. This code exists to
|
||||
# avoid ending up with both, Qt::Foo and Foo in our dependencies.
|
||||
set(namespaceless_lib_target "${CMAKE_MATCH_1}")
|
||||
if(TARGET namespaceless_lib_target)
|
||||
set(lib_target ${namespaceless_lib_target})
|
||||
endif()
|
||||
endif()
|
||||
get_target_property(lib_target_type ${lib_target} TYPE)
|
||||
if(lib_target_type STREQUAL "INTERFACE_LIBRARY")
|
||||
qt_internal_walk_libs(
|
||||
${lib_target}
|
||||
lib_libs_${target}
|
||||
lib_rcc_objects_${target}
|
||||
"${dict_name}" "${operation}" ${collected})
|
||||
if(lib_libs_${target})
|
||||
qt_merge_libs(libs ${lib_libs_${target}})
|
||||
set(is_module 0)
|
||||
endif()
|
||||
if(lib_rcc_objects_${target})
|
||||
qt_merge_libs(rcc_objects ${lib_rcc_objects_${target}})
|
||||
endif()
|
||||
elseif(NOT lib_target_type STREQUAL "OBJECT_LIBRARY")
|
||||
qt_merge_libs(libs "$<TARGET_LINKER_FILE:${lib_target}>")
|
||||
|
||||
get_target_property(target_rcc_objects "${lib_target}" _qt_rcc_objects)
|
||||
if(target_rcc_objects)
|
||||
qt_merge_libs(rcc_objects ${target_rcc_objects})
|
||||
endif()
|
||||
|
||||
qt_internal_walk_libs(
|
||||
${lib_target}
|
||||
lib_libs_${target}
|
||||
lib_rcc_objects_${target}
|
||||
"${dict_name}" "${operation}" ${collected})
|
||||
if(lib_libs_${target})
|
||||
qt_merge_libs(libs ${lib_libs_${target}})
|
||||
endif()
|
||||
if(lib_rcc_objects_${target})
|
||||
qt_merge_libs(rcc_objects ${lib_rcc_objects_${target}})
|
||||
endif()
|
||||
endif()
|
||||
if(operation STREQUAL "promote_global")
|
||||
set(lib_target_unaliased "${lib_target}")
|
||||
get_target_property(aliased_target ${lib_target} ALIASED_TARGET)
|
||||
if(aliased_target)
|
||||
set(lib_target_unaliased ${aliased_target})
|
||||
endif()
|
||||
|
||||
get_property(is_imported TARGET ${lib_target_unaliased} PROPERTY IMPORTED)
|
||||
get_property(is_global TARGET ${lib_target_unaliased} PROPERTY IMPORTED_GLOBAL)
|
||||
|
||||
# Allow opting out of promotion. This is useful in certain corner cases
|
||||
# like with WrapLibClang and Threads in qttools.
|
||||
qt_internal_should_not_promote_package_target_to_global(
|
||||
"${lib_target_unaliased}" should_not_promote)
|
||||
if(NOT is_global AND is_imported AND NOT should_not_promote)
|
||||
set_property(TARGET ${lib_target_unaliased} PROPERTY IMPORTED_GLOBAL TRUE)
|
||||
endif()
|
||||
endif()
|
||||
elseif("${lib_target}" MATCHES "^Qt::(.*)")
|
||||
message(FATAL_ERROR "The ${CMAKE_MATCH_1} target is mentioned as a dependency for \
|
||||
${target}, but not declared.")
|
||||
else()
|
||||
set(final_lib_name_to_merge "${lib_target}")
|
||||
if(lib_target MATCHES "/([^/]+).framework$")
|
||||
set(final_lib_name_to_merge "-framework ${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
qt_merge_libs(libs "${final_lib_name_to_merge}")
|
||||
endif()
|
||||
endforeach()
|
||||
qt_internal_memoize_values_in_dict("${target}" "${dict_name}" "libs" "${libs}")
|
||||
qt_internal_memoize_values_in_dict("${target}" "${dict_name}"
|
||||
"rcc_objects" "${rcc_objects}")
|
||||
|
||||
endif()
|
||||
set(${out_var} ${libs} PARENT_SCOPE)
|
||||
set(${rcc_objects_out_var} ${rcc_objects} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Generate a qmake .prl file for the given target.
|
||||
# The install_dir argument is a relative path, for example "lib".
|
||||
function(qt_generate_prl_file target install_dir)
|
||||
|
16
cmake/QtPublicTargetHelpers.cmake
Normal file
16
cmake/QtPublicTargetHelpers.cmake
Normal file
@ -0,0 +1,16 @@
|
||||
function(__qt_internal_strip_target_directory_scope_token target out_var)
|
||||
# In CMake versions earlier than CMake 3.18, a subdirectory scope id is appended to the
|
||||
# target name if the target is referenced in a target_link_libraries command from a
|
||||
# different directory scope than where the target was created.
|
||||
# Strip it.
|
||||
#
|
||||
# For informational purposes, in CMake 3.18, the target name looks as follows:
|
||||
# ::@(0x5604cb3f6b50);Threads::Threads;::@
|
||||
# This case doesn't have to be stripped (at least for now), because when we iterate over
|
||||
# link libraries, the tokens appear as separate target names.
|
||||
#
|
||||
# Example: Threads::Threads::@<0x5604cb3f6b50>
|
||||
# Output: Threads::Threads
|
||||
string(REGEX REPLACE "::@<.+>$" "" target "${target}")
|
||||
set("${out_var}" "${target}" PARENT_SCOPE)
|
||||
endfunction()
|
237
cmake/QtPublicWalkLibsHelpers.cmake
Normal file
237
cmake/QtPublicWalkLibsHelpers.cmake
Normal file
@ -0,0 +1,237 @@
|
||||
# Add libraries to variable ${out_libs_var} in a way that duplicates
|
||||
# are added at the end. This ensures the library order needed for the
|
||||
# linker.
|
||||
function(__qt_internal_merge_libs out_libs_var)
|
||||
foreach(dep ${ARGN})
|
||||
list(REMOVE_ITEM ${out_libs_var} ${dep})
|
||||
list(APPEND ${out_libs_var} ${dep})
|
||||
endforeach()
|
||||
set(${out_libs_var} ${${out_libs_var}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
# Extracts value from per-target dict key and assigns it to out_var.
|
||||
# Assumes dict_name to be an existing INTERFACE target.
|
||||
function(__qt_internal_get_dict_key_values out_var target_infix dict_name dict_key)
|
||||
get_target_property(values "${dict_name}" "INTERFACE_${target_infix}_${dict_key}")
|
||||
set(${out_var} "${values}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
# Assigns 'values' to per-target dict key, including for aliases of the target.
|
||||
# Assumes dict_name to be an existing INTERFACE target.
|
||||
function(__qt_internal_memoize_values_in_dict target dict_name dict_key values)
|
||||
# Memoize the computed values for the target as well as its aliases.
|
||||
#
|
||||
# Aka assigns the contents of ${values} to INTERFACE_Core, INTERFACE_Qt::Core,
|
||||
# INTERFACE_Qt6::Core.
|
||||
#
|
||||
# Yes, i know it's crazy that target names are legal property names.
|
||||
#
|
||||
# Assigning for library aliases is needed to avoid multiple recomputation of values.
|
||||
# Scenario in the context of __qt_internal_walk_libs:
|
||||
# 'values' are computed for Core target and memoized to INTERFACE_Core.
|
||||
# When processing Gui, it depends on Qt::Core, but there are no values for INTERFACE_Qt::Core.
|
||||
set_target_properties(${dict_name} PROPERTIES INTERFACE_${target}_${dict_key} "${values}")
|
||||
|
||||
get_target_property(versionless_alias "${target}" "_qt_versionless_alias")
|
||||
if(versionless_alias)
|
||||
__qt_internal_get_dict_key_values(
|
||||
versionless_values "${versionless_alias}" "${dict_name}" "${dict_key}")
|
||||
if(versionless_values MATCHES "-NOTFOUND$")
|
||||
set_target_properties(${dict_name}
|
||||
PROPERTIES INTERFACE_${versionless_alias}_${dict_key} "${values}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
get_target_property(versionfull_alias "${target}" "_qt_versionfull_alias")
|
||||
if(versionfull_alias)
|
||||
__qt_internal_get_dict_key_values(
|
||||
versionfull_values "${versionfull_alias}" "${dict_name}" "${dict_key}")
|
||||
if(versionfull_values MATCHES "-NOTFOUND$")
|
||||
set_target_properties(${dict_name}
|
||||
PROPERTIES INTERFACE_${versionfull_alias}_${dict_key} "${values}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
# Walks a target's link libraries recursively, and performs some actions (poor man's polypmorphism)
|
||||
#
|
||||
# out_var is the name of the variable where the result will be assigned. The result is a list of
|
||||
# libraries, mostly in generator expression form.
|
||||
# rcc_objects_out_var is the name of the variable where the collected rcc object files will be
|
||||
# assigned (for the initial target and its dependencies)
|
||||
# dict_name is used for caching the results, and preventing the same target from being processed
|
||||
# twice
|
||||
# operation is a string to tell the function what additional behaviors to execute.
|
||||
function(__qt_internal_walk_libs
|
||||
target out_var rcc_objects_out_var dict_name operation)
|
||||
set(collected ${ARGN})
|
||||
if(target IN_LIST collected)
|
||||
return()
|
||||
endif()
|
||||
list(APPEND collected ${target})
|
||||
|
||||
if(target STREQUAL "${QT_CMAKE_EXPORT_NAMESPACE}::EntryPoint")
|
||||
# We can't (and don't need to) process EntryPoint because it brings in $<TARGET_PROPERTY:prop>
|
||||
# genexes which get replaced with $<TARGET_PROPERTY:EntryPoint,prop> genexes in the code below
|
||||
# and that causes 'INTERFACE_LIBRARY targets may only have whitelisted properties.' errors
|
||||
# with CMake versions equal to or lower than 3.18. These errors are super unintuitive to
|
||||
# debug because there's no mention that it's happening during a file(GENERATE) call.
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET ${dict_name})
|
||||
add_library(${dict_name} INTERFACE IMPORTED GLOBAL)
|
||||
endif()
|
||||
__qt_internal_get_dict_key_values(libs "${target}" "${dict_name}" "libs")
|
||||
__qt_internal_get_dict_key_values(rcc_objects "${target}" "${dict_name}" "rcc_objects")
|
||||
|
||||
if(libs MATCHES "-NOTFOUND$")
|
||||
unset(libs)
|
||||
unset(rcc_objects)
|
||||
get_target_property(target_libs ${target} INTERFACE_LINK_LIBRARIES)
|
||||
if(NOT target_libs)
|
||||
unset(target_libs)
|
||||
endif()
|
||||
get_target_property(target_type ${target} TYPE)
|
||||
if(target_type STREQUAL "STATIC_LIBRARY")
|
||||
get_target_property(link_libs ${target} LINK_LIBRARIES)
|
||||
if(link_libs)
|
||||
list(APPEND target_libs ${link_libs})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Need to record the rcc object file info not only for dependencies, but also for
|
||||
# the current target too. Otherwise the saved information is incomplete for prl static
|
||||
# build purposes.
|
||||
get_target_property(main_target_rcc_objects ${target} _qt_rcc_objects)
|
||||
if(main_target_rcc_objects)
|
||||
__qt_internal_merge_libs(rcc_objects ${main_target_rcc_objects})
|
||||
endif()
|
||||
|
||||
foreach(lib ${target_libs})
|
||||
# Cannot use $<TARGET_POLICY:...> in add_custom_command.
|
||||
# Check the policy now, and replace the generator expression with the value.
|
||||
while(lib MATCHES "\\$<TARGET_POLICY:([^>]+)>")
|
||||
cmake_policy(GET ${CMAKE_MATCH_1} value)
|
||||
if(value STREQUAL "NEW")
|
||||
set(value "TRUE")
|
||||
else()
|
||||
set(value "FALSE")
|
||||
endif()
|
||||
string(REPLACE "${CMAKE_MATCH_0}" "${value}" lib "${lib}")
|
||||
endwhile()
|
||||
|
||||
# Fix up $<TARGET_PROPERTY:FOO> expressions that refer to the "current" target.
|
||||
# Those cannot be used with add_custom_command.
|
||||
while(lib MATCHES "\\$<TARGET_PROPERTY:([^,>]+)>")
|
||||
string(REPLACE "${CMAKE_MATCH_0}" "$<TARGET_PROPERTY:${target},${CMAKE_MATCH_1}>"
|
||||
lib "${lib}")
|
||||
endwhile()
|
||||
|
||||
# Skip static plugins.
|
||||
set(_is_plugin_marker_genex "\\$<BOOL:QT_IS_PLUGIN_GENEX>")
|
||||
if(lib MATCHES "${_is_plugin_marker_genex}")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# Strip any directory scope tokens.
|
||||
__qt_internal_strip_target_directory_scope_token("${lib}" lib)
|
||||
|
||||
if(lib MATCHES "^\\$<TARGET_OBJECTS:")
|
||||
# Skip object files.
|
||||
continue()
|
||||
elseif(lib MATCHES "^\\$<LINK_ONLY:(.*)>$")
|
||||
set(lib_target ${CMAKE_MATCH_1})
|
||||
else()
|
||||
set(lib_target ${lib})
|
||||
endif()
|
||||
|
||||
# Skip CMAKE_DIRECTORY_ID_SEP. If a target_link_libraries is applied to a target
|
||||
# that was defined in a different scope, CMake appends and prepends a special directory
|
||||
# id separator. Filter those out.
|
||||
if(lib_target MATCHES "^::@")
|
||||
continue()
|
||||
elseif(TARGET ${lib_target})
|
||||
if ("${lib_target}" MATCHES "^Qt::(.*)")
|
||||
# If both, Qt::Foo and Foo targets exist, prefer the target name without
|
||||
# namespace. Which one is preferred doesn't really matter. This code exists to
|
||||
# avoid ending up with both, Qt::Foo and Foo in our dependencies.
|
||||
set(namespaceless_lib_target "${CMAKE_MATCH_1}")
|
||||
if(TARGET namespaceless_lib_target)
|
||||
set(lib_target ${namespaceless_lib_target})
|
||||
endif()
|
||||
endif()
|
||||
get_target_property(lib_target_type ${lib_target} TYPE)
|
||||
if(lib_target_type STREQUAL "INTERFACE_LIBRARY")
|
||||
__qt_internal_walk_libs(
|
||||
${lib_target}
|
||||
lib_libs_${target}
|
||||
lib_rcc_objects_${target}
|
||||
"${dict_name}" "${operation}" ${collected})
|
||||
if(lib_libs_${target})
|
||||
__qt_internal_merge_libs(libs ${lib_libs_${target}})
|
||||
set(is_module 0)
|
||||
endif()
|
||||
if(lib_rcc_objects_${target})
|
||||
__qt_internal_merge_libs(rcc_objects ${lib_rcc_objects_${target}})
|
||||
endif()
|
||||
elseif(NOT lib_target_type STREQUAL "OBJECT_LIBRARY")
|
||||
__qt_internal_merge_libs(libs "$<TARGET_LINKER_FILE:${lib_target}>")
|
||||
|
||||
get_target_property(target_rcc_objects "${lib_target}" _qt_rcc_objects)
|
||||
if(target_rcc_objects)
|
||||
__qt_internal_merge_libs(rcc_objects ${target_rcc_objects})
|
||||
endif()
|
||||
|
||||
__qt_internal_walk_libs(
|
||||
${lib_target}
|
||||
lib_libs_${target}
|
||||
lib_rcc_objects_${target}
|
||||
"${dict_name}" "${operation}" ${collected})
|
||||
if(lib_libs_${target})
|
||||
__qt_internal_merge_libs(libs ${lib_libs_${target}})
|
||||
endif()
|
||||
if(lib_rcc_objects_${target})
|
||||
__qt_internal_merge_libs(rcc_objects ${lib_rcc_objects_${target}})
|
||||
endif()
|
||||
endif()
|
||||
if(operation STREQUAL "promote_global")
|
||||
set(lib_target_unaliased "${lib_target}")
|
||||
get_target_property(aliased_target ${lib_target} ALIASED_TARGET)
|
||||
if(aliased_target)
|
||||
set(lib_target_unaliased ${aliased_target})
|
||||
endif()
|
||||
|
||||
get_property(is_imported TARGET ${lib_target_unaliased} PROPERTY IMPORTED)
|
||||
get_property(is_global TARGET ${lib_target_unaliased} PROPERTY IMPORTED_GLOBAL)
|
||||
|
||||
# Allow opting out of promotion. This is useful in certain corner cases
|
||||
# like with WrapLibClang and Threads in qttools.
|
||||
qt_internal_should_not_promote_package_target_to_global(
|
||||
"${lib_target_unaliased}" should_not_promote)
|
||||
if(NOT is_global AND is_imported AND NOT should_not_promote)
|
||||
set_property(TARGET ${lib_target_unaliased} PROPERTY IMPORTED_GLOBAL TRUE)
|
||||
endif()
|
||||
endif()
|
||||
elseif("${lib_target}" MATCHES "^Qt::(.*)")
|
||||
message(FATAL_ERROR "The ${CMAKE_MATCH_1} target is mentioned as a dependency for \
|
||||
${target}, but not declared.")
|
||||
else()
|
||||
set(final_lib_name_to_merge "${lib_target}")
|
||||
if(lib_target MATCHES "/([^/]+).framework$")
|
||||
set(final_lib_name_to_merge "-framework ${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
__qt_internal_merge_libs(libs "${final_lib_name_to_merge}")
|
||||
endif()
|
||||
endforeach()
|
||||
__qt_internal_memoize_values_in_dict("${target}" "${dict_name}" "libs" "${libs}")
|
||||
__qt_internal_memoize_values_in_dict("${target}" "${dict_name}"
|
||||
"rcc_objects" "${rcc_objects}")
|
||||
|
||||
endif()
|
||||
set(${out_var} ${libs} PARENT_SCOPE)
|
||||
set(${rcc_objects_out_var} ${rcc_objects} PARENT_SCOPE)
|
||||
endfunction()
|
@ -264,23 +264,6 @@ function(qt_internal_check_directory_or_type name dir type default result_var)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(qt_internal_strip_target_directory_scope_token target out_var)
|
||||
# In CMake versions earlier than CMake 3.18, a subdirectory scope id is appended to the
|
||||
# target name if the target is referenced in a target_link_libraries command from a
|
||||
# different directory scope than where the target was created.
|
||||
# Strip it.
|
||||
#
|
||||
# For informational purposes, in CMake 3.18, the target name looks as follows:
|
||||
# ::@(0x5604cb3f6b50);Threads::Threads;::@
|
||||
# This case doesn't have to be stripped (at least for now), because when we iterate over
|
||||
# link libraries, the tokens appear as separate target names.
|
||||
#
|
||||
# Example: Threads::Threads::@<0x5604cb3f6b50>
|
||||
# Output: Threads::Threads
|
||||
string(REGEX REPLACE "::@<.+>$" "" target "${target}")
|
||||
set("${out_var}" "${target}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Create a Qt*AdditionalTargetInfo.cmake file that is included by Qt*Config.cmake
|
||||
# and sets IMPORTED_*_<CONFIG> properties on the exported targets.
|
||||
#
|
||||
|
Loading…
x
Reference in New Issue
Block a user