diff options
-rw-r--r-- | cmake/QtFindPackageHelpers.cmake | 3 | ||||
-rw-r--r-- | cmake/QtPluginHelpers.cmake | 2 | ||||
-rw-r--r-- | cmake/QtPublicTargetHelpers.cmake | 14 | ||||
-rw-r--r-- | cmake/QtPublicWalkLibsHelpers.cmake | 5 | ||||
-rw-r--r-- | cmake/QtResourceHelpers.cmake | 4 | ||||
-rw-r--r-- | cmake/QtScopeFinalizerHelpers.cmake | 3 | ||||
-rw-r--r-- | cmake/QtTargetHelpers.cmake | 135 | ||||
-rw-r--r-- | cmake/QtToolHelpers.cmake | 5 | ||||
-rw-r--r-- | tests/auto/cmake/CMakeLists.txt | 4 | ||||
-rw-r--r-- | tests/auto/cmake/test_global_promotion/CMakeLists.txt | 13 | ||||
-rw-r--r-- | tests/auto/cmake/test_global_promotion/subdir_with_global_qt/CMakeLists.txt | 14 | ||||
-rw-r--r-- | tests/auto/cmake/test_global_promotion/subdir_with_local_qt/CMakeLists.txt | 12 |
12 files changed, 197 insertions, 17 deletions
diff --git a/cmake/QtFindPackageHelpers.cmake b/cmake/QtFindPackageHelpers.cmake index 1853240f22..fca039549e 100644 --- a/cmake/QtFindPackageHelpers.cmake +++ b/cmake/QtFindPackageHelpers.cmake @@ -159,8 +159,7 @@ macro(qt_find_package) qt_internal_should_not_promote_package_target_to_global( "${qt_find_package_target_name}" should_not_promote) if(NOT is_global AND NOT should_not_promote) - set_property(TARGET ${qt_find_package_target_name} PROPERTY - IMPORTED_GLOBAL TRUE) + __qt_internal_promote_target_to_global(${qt_find_package_target_name}) qt_find_package_promote_targets_to_global_scope( "${qt_find_package_target_name}") endif() diff --git a/cmake/QtPluginHelpers.cmake b/cmake/QtPluginHelpers.cmake index c4e0df4415..a7d2720ee4 100644 --- a/cmake/QtPluginHelpers.cmake +++ b/cmake/QtPluginHelpers.cmake @@ -343,7 +343,7 @@ function(qt_internal_add_plugin target) qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix}) qt_internal_export_additional_targets_file( - TARGETS ${target} + TARGETS ${target} ${plugin_init_target} EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target} CONFIG_INSTALL_DIR "${config_install_dir}") diff --git a/cmake/QtPublicTargetHelpers.cmake b/cmake/QtPublicTargetHelpers.cmake index 3804b18ac4..70e6c85b1a 100644 --- a/cmake/QtPublicTargetHelpers.cmake +++ b/cmake/QtPublicTargetHelpers.cmake @@ -114,3 +114,17 @@ function(__qt_internal_collect_resource_objects_recursively out_var target initi endforeach() set(${out_var} "${resource_targets}" PARENT_SCOPE) endfunction() + +function(__qt_internal_promote_target_to_global target) + get_property(is_global TARGET ${target} PROPERTY IMPORTED_GLOBAL) + if(NOT is_global) + message(DEBUG "Promoting target to global: '${target}'") + set_property(TARGET ${target} PROPERTY IMPORTED_GLOBAL TRUE) + endif() +endfunction() + +function(__qt_internal_promote_target_to_global_checked target) + if(QT_PROMOTE_TO_GLOBAL_TARGETS) + __qt_internal_promote_target_to_global(${target}) + endif() +endfunction() diff --git a/cmake/QtPublicWalkLibsHelpers.cmake b/cmake/QtPublicWalkLibsHelpers.cmake index 963c15d4c6..19eef91356 100644 --- a/cmake/QtPublicWalkLibsHelpers.cmake +++ b/cmake/QtPublicWalkLibsHelpers.cmake @@ -222,14 +222,13 @@ function(__qt_internal_walk_libs 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) + if(is_imported AND NOT should_not_promote) + __qt_internal_promote_target_to_global(${lib_target_unaliased}) endif() endif() elseif("${lib_target}" MATCHES "^Qt::(.*)") diff --git a/cmake/QtResourceHelpers.cmake b/cmake/QtResourceHelpers.cmake index 3c719d1dd0..4b7d81cc7f 100644 --- a/cmake/QtResourceHelpers.cmake +++ b/cmake/QtResourceHelpers.cmake @@ -21,6 +21,10 @@ function(qt_internal_add_resource target resourceName) EXPORT "${INSTALL_CMAKE_NAMESPACE}${target}Targets" DESTINATION "${INSTALL_LIBDIR}" ) + qt_internal_add_targets_to_additional_targets_export_file( + TARGETS ${out_targets} + EXPORT_NAME_PREFIX "${INSTALL_CMAKE_NAMESPACE}${target}" + ) qt_internal_record_rcc_object_files("${target}" "${out_targets}" INSTALL_DIRECTORY "${INSTALL_LIBDIR}") diff --git a/cmake/QtScopeFinalizerHelpers.cmake b/cmake/QtScopeFinalizerHelpers.cmake index 59e89cc9e2..6dae635ba2 100644 --- a/cmake/QtScopeFinalizerHelpers.cmake +++ b/cmake/QtScopeFinalizerHelpers.cmake @@ -74,6 +74,9 @@ function(qt_watch_current_list_dir variable access value current_list_file stack qt_finalize_plugin(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9}) elseif(func STREQUAL "qt_internal_finalize_app") qt_internal_finalize_app(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9}) + elseif(func STREQUAL "qt_internal_export_additional_targets_file_finalizer") + qt_internal_export_additional_targets_file_finalizer( + ${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9}) else() message(FATAL_ERROR "qt_watch_current_list_dir doesn't know about ${func}. Consider adding it.") endif() diff --git a/cmake/QtTargetHelpers.cmake b/cmake/QtTargetHelpers.cmake index cc8bfde85f..be1cf5e2da 100644 --- a/cmake/QtTargetHelpers.cmake +++ b/cmake/QtTargetHelpers.cmake @@ -264,9 +264,26 @@ function(qt_internal_check_directory_or_type name dir type default result_var) endif() endfunction() +macro(qt_internal_get_export_additional_targets_keywords option_args single_args multi_args) + set(${option_args} + ) + set(${single_args} + EXPORT_NAME_PREFIX + ) + set(${multi_args} + TARGETS + TARGET_EXPORT_NAMES + ) +endmacro() + # Create a Qt*AdditionalTargetInfo.cmake file that is included by Qt*Config.cmake # and sets IMPORTED_*_<CONFIG> properties on the exported targets. # +# The file also makes the targets global if the QT_PROMOTE_TO_GLOBAL_TARGETS property is set in the +# consuming project. +# Only the specified TARGETS are made global. Transitive 3rd party targets are not made global, due +# to limitations in CMake. See https://gitlab.kitware.com/cmake/cmake/-/issues/22291 +# # EXPORT_NAME_PREFIX: # The portion of the file name before AdditionalTargetInfo.cmake # CONFIG_INSTALL_DIR: @@ -283,14 +300,75 @@ endfunction() # TARGET_EXPORT_NAMES = Qt6::qmljs # function(qt_internal_export_additional_targets_file) - cmake_parse_arguments(arg "" "EXPORT_NAME_PREFIX;CONFIG_INSTALL_DIR" - "TARGETS;TARGET_EXPORT_NAMES" ${ARGN}) + qt_internal_get_export_additional_targets_keywords(option_args single_args multi_args) + cmake_parse_arguments(arg + "${option_args}" + "${single_args};CONFIG_INSTALL_DIR" + "${multi_args}" + ${ARGN}) + + qt_internal_append_export_additional_targets() + + set_property(GLOBAL APPEND PROPERTY _qt_export_additional_targets_ids "${id}") + set_property(GLOBAL APPEND + PROPERTY _qt_export_additional_targets_export_name_prefix_${id} "${arg_EXPORT_NAME_PREFIX}") + set_property(GLOBAL APPEND + PROPERTY _qt_export_additional_targets_config_install_dir_${id} "${arg_CONFIG_INSTALL_DIR}") + + qt_add_list_file_finalizer(qt_internal_export_additional_targets_file_finalizer) +endfunction() + +function(qt_internal_get_export_additional_targets_id export_name out_var) + string(MAKE_C_IDENTIFIER "${export_name}" id) + set(${out_var} "${id}" PARENT_SCOPE) +endfunction() + +# Uses outer-scope variables to keep the implementation less verbose. +macro(qt_internal_append_export_additional_targets) + qt_internal_validate_export_additional_targets( + EXPORT_NAME_PREFIX "${arg_EXPORT_NAME_PREFIX}" + TARGETS ${arg_TARGETS} + TARGET_EXPORT_NAMES ${arg_TARGET_EXPORT_NAMES}) + + qt_internal_get_export_additional_targets_id("${arg_EXPORT_NAME_PREFIX}" id) + + set_property(GLOBAL APPEND + PROPERTY _qt_export_additional_targets_${id} "${arg_TARGETS}") + set_property(GLOBAL APPEND + PROPERTY _qt_export_additional_target_export_names_${id} "${arg_TARGET_EXPORT_NAMES}") +endmacro() + +# Can be called to add additional targets to the file after the initial setup call. +# Used for resources. +function(qt_internal_add_targets_to_additional_targets_export_file) + qt_internal_get_export_additional_targets_keywords(option_args single_args multi_args) + cmake_parse_arguments(arg + "${option_args}" + "${single_args}" + "${multi_args}" + ${ARGN}) + + qt_internal_append_export_additional_targets() +endfunction() + +function(qt_internal_validate_export_additional_targets) + qt_internal_get_export_additional_targets_keywords(option_args single_args multi_args) + cmake_parse_arguments(arg + "${option_args}" + "${single_args}" + "${multi_args}" + ${ARGN}) + + if(NOT arg_EXPORT_NAME_PREFIX) + message(FATAL_ERROR "qt_internal_validate_export_additional_targets: " + "Missing EXPORT_NAME_PREFIX argument.") + endif() list(LENGTH arg_TARGETS num_TARGETS) list(LENGTH arg_TARGET_EXPORT_NAMES num_TARGET_EXPORT_NAMES) if(num_TARGET_EXPORT_NAMES GREATER 0) if(NOT num_TARGETS EQUAL num_TARGET_EXPORT_NAMES) - message(FATAL_ERROR "qt_internal_export_additional_targets_file: " + message(FATAL_ERROR "qt_internal_validate_export_additional_targets: " "TARGET_EXPORT_NAMES is set but has ${num_TARGET_EXPORT_NAMES} elements while " "TARGETS has ${num_TARGETS} elements. " "They must contain the same number of elements.") @@ -299,6 +377,34 @@ function(qt_internal_export_additional_targets_file) set(arg_TARGET_EXPORT_NAMES ${arg_TARGETS}) endif() + set(arg_TARGETS "${arg_TARGETS}" PARENT_SCOPE) + set(arg_TARGET_EXPORT_NAMES "${arg_TARGET_EXPORT_NAMES}" PARENT_SCOPE) +endfunction() + +# The finalizer might be called multiple times in the same scope, but only the first one will +# process all the ids. +function(qt_internal_export_additional_targets_file_finalizer) + get_property(ids GLOBAL PROPERTY _qt_export_additional_targets_ids) + + foreach(id ${ids}) + qt_internal_export_additional_targets_file_handler("${id}") + endforeach() + + set_property(GLOBAL PROPERTY _qt_export_additional_targets_ids "") +endfunction() + +function(qt_internal_export_additional_targets_file_handler id) + get_property(arg_EXPORT_NAME_PREFIX GLOBAL PROPERTY + _qt_export_additional_targets_export_name_prefix_${id}) + get_property(arg_CONFIG_INSTALL_DIR GLOBAL PROPERTY + _qt_export_additional_targets_config_install_dir_${id}) + get_property(arg_TARGETS GLOBAL PROPERTY + _qt_export_additional_targets_${id}) + get_property(arg_TARGET_EXPORT_NAMES GLOBAL PROPERTY + _qt_export_additional_target_export_names_${id}) + + list(LENGTH arg_TARGETS num_TARGETS) + # Determine the release configurations we're currently building if(QT_GENERATOR_IS_MULTI_CONFIG) set(active_configurations ${CMAKE_CONFIGURATION_TYPES}) @@ -337,18 +443,33 @@ if(NOT DEFINED QT_DEFAULT_IMPORT_CONFIGURATION) set(QT_DEFAULT_IMPORT_CONFIGURATION ${uc_default_cfg}) endif() ") + math(EXPR n "${num_TARGETS} - 1") foreach(i RANGE ${n}) list(GET arg_TARGETS ${i} target) list(GET arg_TARGET_EXPORT_NAMES ${i} target_export_name) - get_target_property(target_type ${target} TYPE) - if(target_type STREQUAL "INTERFACE_LIBRARY") - continue() - endif() + set(full_target ${target_export_name}) if(NOT full_target MATCHES "^${QT_CMAKE_EXPORT_NAMESPACE}::") string(PREPEND full_target "${QT_CMAKE_EXPORT_NAMESPACE}::") endif() + + # Tools are already made global unconditionally in QtFooToolsConfig.cmake. + # And the + get_target_property(target_type ${target} TYPE) + if(NOT target_type STREQUAL "EXECUTABLE") + string(APPEND content + "__qt_internal_promote_target_to_global_checked(${full_target})\n") + endif() + + # INTERFACE libraries don't have IMPORTED_LOCATION-like properties. + # OBJECT libraries have properties like IMPORTED_OBJECTS instead. + # Skip the rest of the procesing for those. + if(target_type STREQUAL "INTERFACE_LIBRARY" OR target_type STREQUAL "OBJECT_LIBRARY") + continue() + endif() + + # FIXME: Don't add IMPORTED_SOLIB and IMPORTED_SONAME properties for executables. set(properties_retrieved TRUE) if(NOT "${uc_release_cfg}" STREQUAL "") string(APPEND content "get_target_property(_qt_imported_location ${full_target} IMPORTED_LOCATION_${uc_release_cfg})\n") diff --git a/cmake/QtToolHelpers.cmake b/cmake/QtToolHelpers.cmake index 24ab9e0162..4274e622a4 100644 --- a/cmake/QtToolHelpers.cmake +++ b/cmake/QtToolHelpers.cmake @@ -321,10 +321,7 @@ function(qt_export_tools module_name) endif() set(extra_cmake_statements "${extra_cmake_statements} if (NOT QT_NO_CREATE_TARGETS) - get_property(is_global TARGET ${INSTALL_CMAKE_NAMESPACE}::${tool_name} PROPERTY IMPORTED_GLOBAL) - if(NOT is_global) - set_property(TARGET ${INSTALL_CMAKE_NAMESPACE}::${tool_name} PROPERTY IMPORTED_GLOBAL TRUE) - endif() + __qt_internal_promote_target_to_global(${INSTALL_CMAKE_NAMESPACE}::${tool_name}) endif() ") list(APPEND tool_targets "${QT_CMAKE_EXPORT_NAMESPACE}::${tool_name}") diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt index b95c530640..8852c7e68b 100644 --- a/tests/auto/cmake/CMakeLists.txt +++ b/tests/auto/cmake/CMakeLists.txt @@ -247,6 +247,10 @@ set_tests_properties(test_import_plugins PROPERTIES FIXTURES_REQUIRED build_mock _qt_internal_test_expect_pass(test_versionless_targets) +if(NOT NO_GUI) + _qt_internal_test_expect_pass(test_global_promotion) +endif() + _qt_internal_test_expect_pass(test_add_resources_binary_generated BINARY test_add_resources_binary_generated) diff --git a/tests/auto/cmake/test_global_promotion/CMakeLists.txt b/tests/auto/cmake/test_global_promotion/CMakeLists.txt new file mode 100644 index 0000000000..c59dece81e --- /dev/null +++ b/tests/auto/cmake/test_global_promotion/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.14) + +project(global_promotion) + +add_subdirectory(subdir_with_local_qt) +add_subdirectory(subdir_with_global_qt) + +set(file_path "${CMAKE_CURRENT_BINARY_DIR}/main.cpp") +file(GENERATE OUTPUT "${file_path}" CONTENT "int main() { return 0; }") +add_executable(exe main.cpp) + +# The Qt targets found in the 2nd child directory scope should be available in this scope. +target_link_libraries(exe PRIVATE lib_global_qt) diff --git a/tests/auto/cmake/test_global_promotion/subdir_with_global_qt/CMakeLists.txt b/tests/auto/cmake/test_global_promotion/subdir_with_global_qt/CMakeLists.txt new file mode 100644 index 0000000000..a8808a8c83 --- /dev/null +++ b/tests/auto/cmake/test_global_promotion/subdir_with_global_qt/CMakeLists.txt @@ -0,0 +1,14 @@ +message(STATUS "Entered subdir_with_global_qt subdirectory") + +set(file_path "${CMAKE_CURRENT_BINARY_DIR}/lib.cpp") +file(GENERATE OUTPUT "${file_path}" CONTENT "int foo() { return 42; }") +add_library(lib_global_qt STATIC "${file_path}") + +# These Qt targets will be available in all scopes of the project. +# The previous local targets are simply shadowed. +set(QT_PROMOTE_TO_GLOBAL_TARGETS ON) +find_package(Qt6 REQUIRED COMPONENTS Gui) + +target_link_libraries(lib_global_qt PRIVATE Qt6::Gui) + +message(STATUS "Exiting subdir_with_global_qt subdirectory") diff --git a/tests/auto/cmake/test_global_promotion/subdir_with_local_qt/CMakeLists.txt b/tests/auto/cmake/test_global_promotion/subdir_with_local_qt/CMakeLists.txt new file mode 100644 index 0000000000..1bed5a2f99 --- /dev/null +++ b/tests/auto/cmake/test_global_promotion/subdir_with_local_qt/CMakeLists.txt @@ -0,0 +1,12 @@ +message(STATUS "Entered subdir_with_local_qt subdirectory") + +set(file_path "${CMAKE_CURRENT_BINARY_DIR}/lib.cpp") +file(GENERATE OUTPUT "${file_path}" CONTENT "int foo() { return 42; }") +add_library(lib_local_qt STATIC "${file_path}") + +# These Qt targets will be local to this directory scope. +find_package(Qt6 REQUIRED COMPONENTS Gui) + +target_link_libraries(lib_local_qt PRIVATE Qt6::Gui) + +message(STATUS "Exiting subdir_with_local_qt subdirectory") |