summaryrefslogtreecommitdiffstats
path: root/cmake/QtPublicTargetHelpers.cmake
diff options
context:
space:
mode:
Diffstat (limited to 'cmake/QtPublicTargetHelpers.cmake')
-rw-r--r--cmake/QtPublicTargetHelpers.cmake295
1 files changed, 258 insertions, 37 deletions
diff --git a/cmake/QtPublicTargetHelpers.cmake b/cmake/QtPublicTargetHelpers.cmake
index 3804b18ac4..02d5546560 100644
--- a/cmake/QtPublicTargetHelpers.cmake
+++ b/cmake/QtPublicTargetHelpers.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
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
@@ -15,65 +18,193 @@ function(__qt_internal_strip_target_directory_scope_token target out_var)
set("${out_var}" "${target}" PARENT_SCOPE)
endfunction()
-function(__qt_internal_process_dependency_resource_objects target)
- get_target_property(processed ${target} _qt_resource_object_finalizers_processed)
+# Tests if linker could resolve circular dependencies between object files and static libraries.
+function(__qt_internal_static_link_order_public_test result)
+ # We could trust iOS linker
+ if(IOS)
+ set(QT_HAVE_LINK_ORDER_MATTERS "FALSE" CACHE INTERNAL "Link order matters")
+ endif()
+
+ if(DEFINED QT_HAVE_LINK_ORDER_MATTERS)
+ set(${result} "${QT_HAVE_LINK_ORDER_MATTERS}" PARENT_SCOPE)
+ return()
+ endif()
+
+ if(EXISTS "${QT_CMAKE_DIR}")
+ set(test_source_basedir "${QT_CMAKE_DIR}/..")
+ else()
+ set(test_source_basedir "${_qt_cmake_dir}/${QT_CMAKE_EXPORT_NAMESPACE}")
+ endif()
+
+ try_compile(${result}
+ "${CMAKE_CURRENT_BINARY_DIR}/config.tests/static_link_order"
+ "${test_source_basedir}/config.tests/static_link_order"
+ static_link_order_test
+ static_link_order_test
+ )
+ message(STATUS "Check if linker can resolve circular dependencies - ${${result}}")
+
+ # Invert the result
+ if(${result})
+ set(${result} FALSE)
+ else()
+ set(${result} TRUE)
+ endif()
+
+ set(QT_HAVE_LINK_ORDER_MATTERS "${${result}}" CACHE INTERNAL "Link order matters")
+
+ set(${result} "${${result}}" PARENT_SCOPE)
+endfunction()
+
+# Sets _qt_link_order_matters flag for the target.
+function(__qt_internal_set_link_order_matters target link_order_matters)
+ if(NOT TARGET ${target})
+ message(FATAL_ERROR "Unable to set _qt_link_order_matters flag. ${target} is not a target.")
+ endif()
+
+ get_target_property(aliased_target ${target} ALIASED_TARGET)
+ if(aliased_target)
+ set(target "${aliased_target}")
+ endif()
+
+ if(link_order_matters)
+ set(link_order_matters TRUE)
+ else()
+ set(link_order_matters FALSE)
+ endif()
+ set_target_properties(${target} PROPERTIES _qt_link_order_matters "${link_order_matters}")
+endfunction()
+
+# Function combines __qt_internal_static_link_order_public_test and
+# __qt_internal_set_link_order_matters calls on Qt::Platform target.
+function(__qt_internal_check_link_order_matters)
+ __qt_internal_static_link_order_public_test(
+ link_order_matters
+ )
+ __qt_internal_set_link_order_matters(
+ ${QT_CMAKE_EXPORT_NAMESPACE}::Platform "${link_order_matters}"
+ )
+
+ if("${ARGC}" GREATER "0" AND NOT ARGV0 STREQUAL "")
+ set(${ARGV0} ${link_order_matters} PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Constructs a TARGET_POLICY genex expression if the policy is available.
+function(__qt_internal_get_cmp0099_genex_check result)
+ if(POLICY CMP0099)
+ set(${result} "$<BOOL:$<TARGET_POLICY:CMP0099>>" PARENT_SCOPE)
+ else()
+ set(${result} "$<BOOL:FALSE>" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(__qt_internal_check_cmp0099_available)
+ set(platform_target ${QT_CMAKE_EXPORT_NAMESPACE}::Platform)
+ get_target_property(aliased_target ${platform_target} ALIASED_TARGET)
+ if(aliased_target)
+ set(platform_target "${aliased_target}")
+ endif()
+
+ __qt_internal_get_cmp0099_genex_check(cmp0099_check)
+ set_target_properties(${platform_target} PROPERTIES
+ _qt_cmp0099_policy_check "${cmp0099_check}"
+ )
+
+ set(result TRUE)
+ if(NOT POLICY CMP0099)
+ set(result FALSE)
+ endif()
+
+ if("${ARGC}" GREATER "0" AND NOT ARGV0 STREQUAL "")
+ set(${ARGV0} ${result} PARENT_SCOPE)
+ endif()
+endfunction()
+
+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
+ # to call the finalizer code.
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21)
+ return()
+ endif()
+ 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)
+
+ get_target_property(qt_link_order_matters
+ ${QT_CMAKE_EXPORT_NAMESPACE}::Platform _qt_link_order_matters
+ )
+ __qt_internal_check_finalizer_mode(${target}
+ use_finalizer_mode
+ object_libraries
+ DEFAULT_VALUE "${qt_link_order_matters}"
+ )
- __qt_internal_check_finalizer_mode(${target} use_finalizer_mode resource_objects)
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 "")
+ __qt_internal_get_cmp0099_genex_check(cmp0099_check)
- 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 "$<$<NOT:${cmp0099_check}>:$<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)
+ __qt_internal_get_cmp0099_genex_check(cmp0099_check)
+ 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)
+ string(JOIN "" plugin_objects_genex
+ "$<"
+ "$<AND:"
+ "$<NOT:${cmp0099_check}>,"
+ "${plugin_condition}"
+ ">"
+ ":$<TARGET_OBJECTS:${plugin_object_library}>"
+ ">"
)
+ list(APPEND plugin_objects "${plugin_objects_genex}")
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 "")
@@ -85,32 +216,122 @@ 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)
+ # Extract possible target from exported LINK_ONLY dependencies.
+ # This is super important for traversing backing library dependencies of qml plugins.
+ if(lib MATCHES "^\\$<LINK_ONLY:(.*)>$")
+ set(lib "${CMAKE_MATCH_1}")
+ endif()
if(TARGET ${lib})
get_target_property(aliased_target ${lib} ALIASED_TARGET)
if(aliased_target)
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)
+ 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)
+ # With CMake version 3.21 we use a different mechanism that allows us to promote all targets
+ # within a scope.
+ if(QT_PROMOTE_TO_GLOBAL_TARGETS AND CMAKE_VERSION VERSION_LESS 3.21)
+ __qt_internal_promote_target_to_global(${target})
+ endif()
+endfunction()
+
+function(__qt_internal_promote_targets_in_dir_scope_to_global)
+ # IMPORTED_TARGETS got added in 3.21.
+ if(CMAKE_VERSION VERSION_LESS 3.21)
+ return()
+ endif()
+
+ get_directory_property(targets IMPORTED_TARGETS)
+ foreach(target IN LISTS targets)
+ __qt_internal_promote_target_to_global(${target})
+ endforeach()
+endfunction()
+
+function(__qt_internal_promote_targets_in_dir_scope_to_global_checked)
+ if(QT_PROMOTE_TO_GLOBAL_TARGETS)
+ __qt_internal_promote_targets_in_dir_scope_to_global()
+ endif()
+endfunction()
+
+# This function ends up being called multiple times as part of a find_package(Qt6Foo) call,
+# due sub-packages depending on the Qt6 package. Ensure the finalizer is ran only once per
+# directory scope.
+function(__qt_internal_defer_promote_targets_in_dir_scope_to_global)
+ get_directory_property(is_deferred _qt_promote_targets_is_deferred)
+ if(NOT is_deferred)
+ set_property(DIRECTORY PROPERTY _qt_promote_targets_is_deferred TRUE)
+
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19)
+ cmake_language(DEFER CALL __qt_internal_promote_targets_in_dir_scope_to_global_checked)
+ endif()
+ endif()
+endfunction()
+
+function(_qt_internal_set_up_static_runtime_library target)
+ if(QT_FEATURE_static_runtime)
+ if(MSVC)
+ set_property(TARGET ${target} PROPERTY
+ MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+ elseif(MINGW)
+ get_target_property(target_type ${target} TYPE)
+ if(target_type STREQUAL "EXECUTABLE")
+ set(link_option PRIVATE)
+ else()
+ set(link_option INTERFACE)
+ endif()
+ if(CLANG)
+ target_link_options(${target} ${link_option} "LINKER:-Bstatic")
+ else()
+ target_link_options(${target} ${link_option} "-static")
+ endif()
+ endif()
+ endif()
+endfunction()
+
+function(_qt_internal_warn_about_example_add_subdirectory)
+ # This is set by qt_build_repo_impl_examples() in QtBuildRepoHelpers.cmake, only for developer
+ # builds, to catch examples that are added via add_subdirectory instead of via
+ # qt_internal_add_example.
+ if(QT_WARN_ABOUT_EXAMPLE_ADD_SUBDIRECTORY)
+ get_filename_component(dir_name "${PROJECT_SOURCE_DIR}" NAME)
+ message(AUTHOR_WARNING
+ "It looks like this example project was added via add_subdirectory instead of via "
+ "qt_internal_add_example. This causes issues in certain build configurations. Please "
+ "change the code to use\n qt_internal_add_example(${dir_name})\ninstead."
+ )
+ endif()
endfunction()