Skip to content

Commit

Permalink
Add the check for linker capabilities to resolve circular dependencies
Browse files Browse the repository at this point in the history
'ld' only capable to resolve circular dependencies by wrapping the
suspected static libraries and objects using --start/end-group
arguments. We want to detect if linker is 'ld' at configure time to
decide how to link the resource objects if finalizers are not enabled.

The qt_config_compile_test function is extended with an extra argument
since it's required to pass custom cmake flags to the ld-related test.

Pick-to: 6.2
Change-Id: I484fcc99e2886952d8b0232f37e4e6a35d072931
Reviewed-by: Alexandru Croitor <[email protected]>
  • Loading branch information
semlanik committed Jun 10, 2021
1 parent 60e104a commit 4e901a2
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 5 deletions.
7 changes: 7 additions & 0 deletions cmake/QtBaseGlobalTargets.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ qt_internal_setup_public_platform_target()

# defines PlatformCommonInternal PlatformModuleInternal PlatformPluginInternal PlatformToolInternal
include(QtInternalTargets)
qt_internal_run_common_config_tests()

set(__export_targets Platform
GlobalConfig
Expand Down Expand Up @@ -237,6 +238,12 @@ qt_copy_or_install(FILES
DESTINATION "${__GlobalConfig_install_dir}"
)

# Install public config.tests files.
qt_copy_or_install(DIRECTORY
"cmake/config.tests"
DESTINATION "${__GlobalConfig_install_dir}"
)

# Install public CMake files.
# The functions defined inside can be used in both public projects and while building Qt.
# Usually we put such functions into Qt6CoreMacros.cmake, but that's getting bloated.
Expand Down
38 changes: 38 additions & 0 deletions cmake/QtBuildInternals/QtBuildInternalsConfig.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,11 @@ 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)
Expand Down Expand Up @@ -941,3 +946,36 @@ if ("STANDALONE_TEST" IN_LIST Qt6BuildInternals_FIND_COMPONENTS)
list(GET _qt_core_version_list 2 PROJECT_VERSION_PATCH)
endif()
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")
else()
set_property(GLOBAL PROPERTY QT_LINK_ORDER_MATTERS TRUE)
set(summary_message "yes")
endif()
qt_configure_add_summary_entry(TYPE "message"
ARGS "Linker can resolve circular dependencies"
MESSAGE "${summary_message}"
)
endfunction()

function(qt_internal_run_common_config_tests)
qt_configure_add_summary_section(NAME "Common build options")
qt_internal_static_link_order_test()
qt_configure_end_summary_section()
endfunction()
8 changes: 6 additions & 2 deletions cmake/QtFeature.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ function(qt_config_compile_test name)
endif()

cmake_parse_arguments(arg "" "LABEL;PROJECT_PATH;C_STANDARD;CXX_STANDARD"
"COMPILE_OPTIONS;LIBRARIES;CODE;PACKAGES" ${ARGN})
"COMPILE_OPTIONS;LIBRARIES;CODE;PACKAGES;CMAKE_FLAGS" ${ARGN})

if(arg_PROJECT_PATH)
message(STATUS "Performing Test ${arg_LABEL}")
Expand Down Expand Up @@ -815,8 +815,12 @@ function(qt_config_compile_test name)
endif()
endif()

if(NOT arg_CMAKE_FLAGS)
set(arg_CMAKE_FLAGS "")
endif()

try_compile(HAVE_${name} "${CMAKE_BINARY_DIR}/config.tests/${name}" "${arg_PROJECT_PATH}"
"${name}" CMAKE_FLAGS ${flags})
"${name}" CMAKE_FLAGS ${flags} ${arg_CMAKE_FLAGS})

if(${HAVE_${name}})
set(status_label "Success")
Expand Down
22 changes: 22 additions & 0 deletions cmake/config.tests/static_link_order/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# The test represents the order-related issue that we have with the ld linker.
#
# CMake versions < 3.21.0 produce the following linker line:
# <binary_name> main.cpp -o static_link_order_test libstaticLib.a objlib.cpp.o
# Since 'static_link_order_test' doesn't have direct use of 'staticlib2.cpp.o' symbols
# the translation unit is not linked. When we link objlib.cpp.o it cannot resolve symbols from
# staticlib2.cpp.o.
#
# For now it's only applicable for ld-like linkers. 'lld' has no such issue.
cmake_minimum_required(VERSION 3.14)

project(static_link_order_test LANGUAGES CXX)

add_library(objLib OBJECT objlib.cpp)
add_library(staticLib STATIC staticlib1.cpp staticlib2.cpp)

target_link_libraries(staticLib
INTERFACE objLib "$<TARGET_OBJECTS:objLib>"
)

add_executable(static_link_order_test main.cpp)
target_link_libraries(static_link_order_test PRIVATE staticLib)
33 changes: 33 additions & 0 deletions cmake/config.tests/static_link_order/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the utils of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

void staticLibFunc1();

int main() {
staticLibFunc1();
}
33 changes: 33 additions & 0 deletions cmake/config.tests/static_link_order/objlib.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the utils of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

void staticLibFunc2();

void objLibFunc() {
staticLibFunc2();
}
33 changes: 33 additions & 0 deletions cmake/config.tests/static_link_order/staticlib1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the utils of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

void objLibFunc();

void staticLibFunc1() {
objLibFunc();
}
30 changes: 30 additions & 0 deletions cmake/config.tests/static_link_order/staticlib2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the utils of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

void staticLibFunc2() {
}
16 changes: 15 additions & 1 deletion src/corelib/Qt6CoreMacros.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -1479,10 +1479,24 @@ function(__qt_propagate_generated_resource target resource_name generated_source
"$<NOT:$<STREQUAL:$<TARGET_PROPERTY:TYPE>,STATIC_LIBRARY>>"
)
set(resource_objects "$<TARGET_OBJECTS:$<TARGET_NAME:${resource_target}>>")
target_link_libraries(${target} INTERFACE

set(resource_linking_args ${target} INTERFACE
"$<$<AND:${finalizer_mode_condition},${not_static_condition}>:${resource_objects}>"
)

# TODO: The QT_LINK_ORDER_MATTERS flag is not defined for user projects.
# It makes sense to disable finalizers if linker may resolve circular dependencies
# between objects and static libraries.
# Follow-up changes should set _qt_resource_objects_finalizer_mode to FALSE by default
# and use target_link_libraries for user projects if the order doesn't affect the
# linker work.
get_property(link_order_matters GLOBAL PROPERTY QT_LINK_ORDER_MATTERS)
if(link_order_matters)
target_sources(${resource_linking_args})
else()
target_link_libraries(${resource_linking_args})
endif()

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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ add_test(NAME test_static_resources_propagation_non_qt
COMMAND test_static_resources_propagation_non_qt
)


if(NOT GCC AND NOT MINGW AND NOT CLANG)
get_property(link_order_matters GLOBAL PROPERTY QT_LINK_ORDER_MATTERS)
if(NOT link_order_matters)
## Add the executable using add_executable, expecting resources to be linked regardless of order.
add_executable(test_static_resources_propagation_non_ld main.cpp)
set_target_properties(test_static_resources_propagation_non_ld PROPERTIES
Expand Down

0 comments on commit 4e901a2

Please sign in to comment.