summaryrefslogtreecommitdiffstats
path: root/cmake
diff options
context:
space:
mode:
authorAlexey Edelev <alexey.edelev@qt.io>2021-06-10 19:01:35 +0200
committerAlexey Edelev <alexey.edelev@qt.io>2021-06-16 16:58:45 +0200
commit5fb99e3860eb43f4bacacec7f4a4626cb0159b14 (patch)
tree5f521fbb62d9408d42b3325e831eff5489eb78a0 /cmake
parent1f4b237dade9d0d2ed5439e3834ac22985797561 (diff)
Check the impact of static link order for user projects
For user projects we run the static link order check once 'find_package(Qt6 ...)' is called. If linker can resolve circular dependencies between static libraries and object files we set the _qt_link_order_matters property of the Qt::Platform target. This indicates the use of finalizers is not required and we may rely on CMake-base propagation of resource libraries and resource object files. If linker could not resolve circular dependencies depending on the _qt_resource_objects_finalizer_mode value: - Finalizer will be called and collected resource objects will be linked to the target directly. - Finalizer will be omitted and resource objects will be linked using the target_sources function implicitly. This only propagates resource one level up if consumer links the static library PUBLICly, but all symbols will be resolved correctly since object files are placed in the beginning of the linker line. In the CMake version 3.21 we expect that CMake will take care about the order of the resource object files in a linker line, it's expected that all object files are located at the beginning of the linker line. TODO: Need to confirm that the CMake 3.21 meets the expectations. Amends 4e901a2f99cbfda3b479253ea54b16f02e1c3aa5 Pick-to: 6.2 Task-number: QTBUG-93002 Task-number: QTBUG-94528 Change-Id: Ia68976df8182d3d3007b90c475c1e3928a305339 Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'cmake')
-rw-r--r--cmake/QtBuildInternals/QtBuildInternalsConfig.cmake35
-rw-r--r--cmake/QtConfig.cmake.in5
-rw-r--r--cmake/QtModuleHelpers.cmake8
-rw-r--r--cmake/QtPublicFinalizerHelpers.cmake4
-rw-r--r--cmake/QtPublicTargetHelpers.cmake103
5 files changed, 122 insertions, 33 deletions
diff --git a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake
index 1427f5a5fc..8cbd0b566f 100644
--- a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake
+++ b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake
@@ -372,11 +372,6 @@ macro(qt_build_repo_begin)
qt_build_internals_set_up_private_api()
qt_enable_cmake_languages()
- # QtBase has own call right after definition of internal platform-specific targets.
- if(NOT PROJECT_NAME STREQUAL "QtBase")
- qt_internal_run_common_config_tests()
- endif()
-
# Add global docs targets that will work both for per-repo builds, and super builds.
if(NOT TARGET docs)
add_custom_target(docs)
@@ -950,24 +945,20 @@ if ("STANDALONE_TEST" IN_LIST Qt6BuildInternals_FIND_COMPONENTS)
endif()
function(qt_internal_static_link_order_test)
- if(TARGET ${QT_CMAKE_EXPORT_NAMESPACE}::PlatformCommonInternal)
- get_target_property(linker_options
- ${QT_CMAKE_EXPORT_NAMESPACE}::PlatformCommonInternal INTERFACE_LINK_OPTIONS
- )
- string(JOIN " " linker_options ${linker_options})
- endif()
-
- qt_config_compile_test(static_link_order
- LABEL "Check if linker can resolve circular dependencies"
- PROJECT_PATH "${QT_CMAKE_DIR}/config.tests/static_link_order"
- CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${linker_options}"
- )
-
- if(TEST_static_link_order)
- set_property(GLOBAL PROPERTY QT_LINK_ORDER_MATTERS FALSE)
- set(summary_message "no")
+ # The CMake versions greater than 3.21 take care about the resource object files order in a
+ # linker line, it's expected that all object files are located at the beginning of the linker
+ # line.
+ # No need to run the test.
+ # TODO: This check is added before the actual release of CMake 3.21. So need to check if the
+ # target version meets the expectations.
+ if(CMAKE_VERSION VERSION_LESS 3.21)
+ __qt_internal_check_link_order_matters(${QT_CMAKE_EXPORT_NAMESPACE}::Platform)
+ if(link_order_matters)
+ set(summary_message "no")
+ else()
+ set(summary_message "yes")
+ endif()
else()
- set_property(GLOBAL PROPERTY QT_LINK_ORDER_MATTERS TRUE)
set(summary_message "yes")
endif()
qt_configure_add_summary_entry(TYPE "message"
diff --git a/cmake/QtConfig.cmake.in b/cmake/QtConfig.cmake.in
index 98c06a46f2..35cd3f77ca 100644
--- a/cmake/QtConfig.cmake.in
+++ b/cmake/QtConfig.cmake.in
@@ -61,6 +61,10 @@ include("${CMAKE_CURRENT_LIST_DIR}/QtPublicTargetHelpers.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/QtPublicWalkLibsHelpers.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/QtPublicFindPackageHelpers.cmake")
+if(NOT DEFINED QT_CMAKE_EXPORT_NAMESPACE)
+ set(QT_CMAKE_EXPORT_NAMESPACE @QT_CMAKE_EXPORT_NAMESPACE@)
+endif()
+
# Find required dependencies, if any.
include(CMakeFindDependencyMacro)
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@Dependencies.cmake")
@@ -107,3 +111,4 @@ if (_Qt_NOTFOUND_MESSAGE)
endif()
__qt_internal_defer_promote_targets_in_dir_scope_to_global()
+__qt_internal_check_link_order_matters(@INSTALL_CMAKE_NAMESPACE@::Platform)
diff --git a/cmake/QtModuleHelpers.cmake b/cmake/QtModuleHelpers.cmake
index 31c45f11d3..703ddde21b 100644
--- a/cmake/QtModuleHelpers.cmake
+++ b/cmake/QtModuleHelpers.cmake
@@ -575,14 +575,6 @@ set(QT_LIBINFIX \"${QT_LIBINFIX}\")")
set(extra_cmake_code "")
- if(target STREQUAL Core)
- # Propagate non-build related variables that are needed for consuming Qt packages.
- # Do this in CoreConfig instead of Qt6Config, so that consumers can also use
- # find_package(Qt6Core) instead of find_package(Qt6 COMPONENTS Core)
- string(APPEND extra_cmake_code "
-set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})")
- endif()
-
# Generate metatypes
if(${arg_GENERATE_METATYPES})
# No mention of NO_GENERATE_METATYPES. You should not use it.
diff --git a/cmake/QtPublicFinalizerHelpers.cmake b/cmake/QtPublicFinalizerHelpers.cmake
index 24354654c8..365d4f2a47 100644
--- a/cmake/QtPublicFinalizerHelpers.cmake
+++ b/cmake/QtPublicFinalizerHelpers.cmake
@@ -4,8 +4,8 @@
function(__qt_internal_check_finalizer_mode target out_var finalizer)
get_target_property(value ${target} _qt_${finalizer}_finalizer_mode)
if("${value}" STREQUAL "value-NOTFOUND")
- set_property(TARGET "${target}" PROPERTY _qt_${finalizer}_finalizer_mode "TRUE")
- set(value TRUE)
+ __qt_internal_enable_finalizer_mode(${target} ${finalizer} "TRUE")
+ set(value "TRUE")
endif()
set(${out_var} "${value}" PARENT_SCOPE)
endfunction()
diff --git a/cmake/QtPublicTargetHelpers.cmake b/cmake/QtPublicTargetHelpers.cmake
index 25e8616ac4..c5e9ce7b63 100644
--- a/cmake/QtPublicTargetHelpers.cmake
+++ b/cmake/QtPublicTargetHelpers.cmake
@@ -15,14 +15,115 @@ function(__qt_internal_strip_target_directory_scope_token target out_var)
set("${out_var}" "${target}" PARENT_SCOPE)
endfunction()
+# Tests if linker could resolve circular dependencies between object files and static libraries.
+function(__qt_internal_static_link_order_public_test target result)
+ # We could trust iOS linker
+ if(IOS)
+ set(QT_HAVE_LINK_ORDER_MATTERS_${target} "FALSE" CACHE BOOL "Link order matters")
+ endif()
+
+ if(DEFINED QT_HAVE_LINK_ORDER_MATTERS_${target})
+ set(${result} "${QT_HAVE_LINK_ORDER_MATTERS_${target}}" PARENT_SCOPE)
+ return()
+ endif()
+
+ set(link_options_property LINK_OPTIONS)
+ set(compile_definitions_property COMPILE_DEFINITIONS)
+ get_target_property(type ${target} TYPE)
+ if(type STREQUAL "INTERFACE_LIBRARY")
+ set(link_options_property INTERFACE_LINK_OPTIONS)
+ set(compile_definitions_property INTERFACE_COMPILE_DEFINITIONS)
+ endif()
+
+ get_target_property(linker_options ${target} ${link_options_property})
+ get_target_property(compile_definitions ${target} ${compile_definitions_property})
+ set(linker_options "${CMAKE_EXE_LINKER_FLAGS} ${linker_options}")
+ set(compile_definitions "${CMAKE_CXX_FLAGS} ${compile_definitions}")
+
+ 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()
+
+ set(test_subdir "${target}")
+ string(TOLOWER "${test_subdir}" test_subdir)
+ string(MAKE_C_IDENTIFIER "${test_subdir}" test_subdir)
+ try_compile(${result}
+ "${CMAKE_CURRENT_BINARY_DIR}/${test_subdir}/config.tests/static_link_order"
+ "${test_source_basedir}/config.tests/static_link_order"
+ static_link_order_test
+ static_link_order_test
+ CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${linker_options}"
+ "-DCMAKE_CXX_FLAGS:STRING=${compile_definitions}"
+ )
+ message(STATUS "Check if linker can resolve circular dependencies for target ${target} \
+- ${${result}}")
+
+ # Invert the result
+ if(${result})
+ set(${result} FALSE)
+ else()
+ set(${result} TRUE)
+ endif()
+
+ set(QT_HAVE_LINK_ORDER_MATTERS_${target} "${${result}}" CACHE BOOL "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 for the target.
+function(__qt_internal_check_link_order_matters target)
+ __qt_internal_static_link_order_public_test(
+ ${target} link_order_matters
+ )
+ __qt_internal_set_link_order_matters(
+ ${target} "${link_order_matters}"
+ )
+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
+ # 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.
+ # TODO: This check is added before the actual release of CMake 3.21. So need to confirm that the
+ # target version meets the expectations.
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21)
+ return()
+ endif()
get_target_property(processed ${target} _qt_resource_object_finalizers_processed)
if(processed)
return()
endif()
set_target_properties(${target} PROPERTIES _qt_resource_object_finalizers_processed TRUE)
- __qt_internal_check_finalizer_mode(${target} use_finalizer_mode resource_objects)
+ __qt_internal_check_finalizer_mode(${target}
+ use_finalizer_mode
+ resource_objects
+ )
+
if(NOT use_finalizer_mode)
return()
endif()