CMake: Only load Qt6FooPrivate automatically when building Qt
[ChangeLog][CMake] CMake packages of public Qt modules don't provide the targets of their private counterparts anymore. User projects must now call find_package(Qt6 COMPONENTS FooPrivate) to make use of the Qt6::FooPrivate target. User projects that rely on the old behavior can set the CMake variable QT_FIND_PRIVATE_MODULES to ON. For user projects, the warning message we know from QMake is displayed. The warning can be disabled by setting the CMake variable QT_NO_PRIVATE_MODULE_WARNING to ON. Within Qt itself, find_package(Qt6Foo) will still find_package(Qt6FooPrivate). For static Qt builds, we need to wrap usage of private Qt modules in $<BUILD_INTERFACE> or $<BUILD_LOCAL_INTERFACE> (if CMake's version is >= 3.26). Static builds with CMake < 3.26 will always load the private modules if the Qt6FooConfig.cmake from Qt's build tree is loaded. This is the case in non-prefix builds and (in the future) when building examples as external project. This amends commit fbbf4ace0188b9718b6d7808021c0b887fd52d9f. Pick-to: 6.9 Task-number: QTBUG-87776 Change-Id: I78e95248f2b3fa73c3005c61df2fe4f71ad8eeb8 Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
This commit is contained in:
parent
cf9c94e851
commit
ad7b94e163
@ -32,26 +32,35 @@ if (NOT QT_NO_CREATE_TARGETS AND @INSTALL_CMAKE_NAMESPACE@@target@_FOUND)
|
||||
endif()
|
||||
|
||||
# Find the private module counterpart.
|
||||
if (@INSTALL_CMAKE_NAMESPACE@@target@_FOUND AND NOT @arg_NO_PRIVATE_MODULE@)
|
||||
if(NOT @INSTALL_CMAKE_NAMESPACE@@target_private@_FOUND)
|
||||
if("${_qt_cmake_dir}" STREQUAL "")
|
||||
set(_qt_cmake_dir "${QT_TOOLCHAIN_RELOCATABLE_CMAKE_DIR}")
|
||||
endif()
|
||||
set(__qt_use_no_default_path_for_qt_packages "NO_DEFAULT_PATH")
|
||||
if(QT_DISABLE_NO_DEFAULT_PATH_IN_QT_PACKAGES)
|
||||
set(__qt_use_no_default_path_for_qt_packages "")
|
||||
endif()
|
||||
find_package(@INSTALL_CMAKE_NAMESPACE@@target_private@ "@PROJECT_VERSION@" EXACT
|
||||
QUIET
|
||||
CONFIG
|
||||
PATHS
|
||||
${QT_BUILD_CMAKE_PREFIX_PATH}
|
||||
"${CMAKE_CURRENT_LIST_DIR}/.."
|
||||
"${_qt_cmake_dir}"
|
||||
${_qt_additional_packages_prefix_paths}
|
||||
${__qt_use_no_default_path_for_qt_packages}
|
||||
set(__qt_@target@_always_load_private_module OFF)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@-build.cmake" OPTIONAL)
|
||||
if (@INSTALL_CMAKE_NAMESPACE@@target@_FOUND
|
||||
AND NOT @INSTALL_CMAKE_NAMESPACE@@target_private@_FOUND
|
||||
AND NOT @arg_NO_PRIVATE_MODULE@
|
||||
AND (
|
||||
__qt_@target@_always_load_private_module
|
||||
OR DEFINED QT_REPO_MODULE_VERSION
|
||||
OR QT_FIND_PRIVATE_MODULES
|
||||
)
|
||||
)
|
||||
if("${_qt_cmake_dir}" STREQUAL "")
|
||||
set(_qt_cmake_dir "${QT_TOOLCHAIN_RELOCATABLE_CMAKE_DIR}")
|
||||
endif()
|
||||
set(__qt_use_no_default_path_for_qt_packages "NO_DEFAULT_PATH")
|
||||
if(QT_DISABLE_NO_DEFAULT_PATH_IN_QT_PACKAGES)
|
||||
set(__qt_use_no_default_path_for_qt_packages "")
|
||||
endif()
|
||||
find_package(@INSTALL_CMAKE_NAMESPACE@@target_private@ "@PROJECT_VERSION@" EXACT
|
||||
QUIET
|
||||
CONFIG
|
||||
PATHS
|
||||
${QT_BUILD_CMAKE_PREFIX_PATH}
|
||||
"${CMAKE_CURRENT_LIST_DIR}/.."
|
||||
"${_qt_cmake_dir}"
|
||||
${_qt_additional_packages_prefix_paths}
|
||||
${__qt_use_no_default_path_for_qt_packages}
|
||||
)
|
||||
|
||||
if(NOT @INSTALL_CMAKE_NAMESPACE@@target_private@_FOUND)
|
||||
get_property(@INSTALL_CMAKE_NAMESPACE@@target_private@_warning_shown GLOBAL PROPERTY
|
||||
@INSTALL_CMAKE_NAMESPACE@@target_private@_warning_shown
|
||||
@ -68,6 +77,7 @@ if (@INSTALL_CMAKE_NAMESPACE@@target@_FOUND AND NOT @arg_NO_PRIVATE_MODULE@)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
unset(__qt_@target@_always_load_private_module)
|
||||
|
||||
if (NOT QT_NO_CREATE_TARGETS AND @INSTALL_CMAKE_NAMESPACE@@target@_FOUND)
|
||||
# DEPRECATED
|
||||
|
@ -20,6 +20,20 @@ if(NOT DEFINED "@INSTALL_CMAKE_NAMESPACE@@target_private@_FOUND")
|
||||
set("@INSTALL_CMAKE_NAMESPACE@@target_private@_FOUND" TRUE)
|
||||
endif()
|
||||
|
||||
if(NOT __qt_@target@_always_load_private_module
|
||||
AND NOT DEFINED QT_REPO_MODULE_VERSION
|
||||
AND NOT QT_NO_PRIVATE_MODULE_WARNING
|
||||
AND NOT __qt_private_module_@target_private@_warning_shown)
|
||||
message(WARNING
|
||||
"This project is using headers of the @target_private@ module and will therefore be tied "
|
||||
"to this specific Qt module build version. "
|
||||
"Running this project against other versions of the Qt modules may crash at any arbitrary "
|
||||
"point. This is not a bug, but a result of using Qt internals. You have been warned! "
|
||||
"\nYou can disable this warning by setting QT_NO_PRIVATE_MODULE_WARNING to ON."
|
||||
)
|
||||
set(__qt_private_module_@target_private@_warning_shown TRUE)
|
||||
endif()
|
||||
|
||||
if(NOT QT_NO_CREATE_TARGETS AND @INSTALL_CMAKE_NAMESPACE@@target_private@_FOUND)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target_private@Targets.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target_private@AdditionalTargetInfo.cmake")
|
||||
|
@ -327,7 +327,7 @@ function(qt_internal_add_module target)
|
||||
set_target_properties(${target_private} PROPERTIES
|
||||
_qt_config_module_name ${arg_CONFIG_MODULE_NAME}_private
|
||||
_qt_package_version "${PROJECT_VERSION}"
|
||||
_qt_package_name "${INSTALL_CMAKE_NAMESPACE}${target}"
|
||||
_qt_package_name "${INSTALL_CMAKE_NAMESPACE}${target}Private"
|
||||
_qt_is_private_module TRUE
|
||||
_qt_public_module_target_name "${target}"
|
||||
)
|
||||
@ -790,7 +790,14 @@ set(QT_ALLOW_MISSING_TOOLS_PACKAGES TRUE)")
|
||||
|
||||
qt_internal_get_min_new_policy_cmake_version(min_new_policy_version)
|
||||
qt_internal_get_max_new_policy_cmake_version(max_new_policy_version)
|
||||
|
||||
if(is_static_lib)
|
||||
set(write_basic_module_package_args IS_STATIC_LIB)
|
||||
else()
|
||||
set(write_basic_module_package_args "")
|
||||
endif()
|
||||
qt_internal_write_basic_module_package("${target}" "${target_private}"
|
||||
${write_basic_module_package_args}
|
||||
CONFIG_BUILD_DIR ${config_build_dir}
|
||||
CONFIG_INSTALL_DIR ${config_install_dir}
|
||||
)
|
||||
@ -809,7 +816,8 @@ set(QT_ALLOW_MISSING_TOOLS_PACKAGES TRUE)")
|
||||
)
|
||||
|
||||
if(NOT arg_NO_PRIVATE_MODULE)
|
||||
qt_internal_write_basic_module_package(${target} ${target_private}
|
||||
qt_internal_write_basic_module_package("${target}" "${target_private}"
|
||||
${write_basic_module_package_args}
|
||||
PRIVATE
|
||||
CONFIG_BUILD_DIR ${private_config_build_dir}
|
||||
CONFIG_INSTALL_DIR ${private_config_install_dir}
|
||||
@ -981,11 +989,9 @@ endfunction()
|
||||
#
|
||||
# If PRIVATE is specified, write Qt6FooPrivate.
|
||||
# Otherwise write its public counterpart.
|
||||
#
|
||||
# Note that this function is supposed to be called from qt_internal_add_module, and depends on
|
||||
# variables set in the scope of that function, e.g. target and target_private.
|
||||
function(qt_internal_write_basic_module_package)
|
||||
function(qt_internal_write_basic_module_package target target_private)
|
||||
set(no_value_options
|
||||
IS_STATIC_LIB
|
||||
PRIVATE
|
||||
)
|
||||
set(single_value_options
|
||||
@ -1005,6 +1011,23 @@ function(qt_internal_write_basic_module_package)
|
||||
set(module_config_input_file "QtModuleConfig.cmake.in")
|
||||
endif()
|
||||
|
||||
if(arg_IS_STATIC_LIB AND NOT arg_PRIVATE AND CMAKE_VERSION VERSION_LESS "3.26")
|
||||
# We auto-load the private module package from the public module package if we have a static
|
||||
# Qt module and CMake's version is < 3.26. This is needed for the case "Qt6Foo links against
|
||||
# Qt6BarPrivate", because CMake generates a check for the target Qt6::BarPrivate in
|
||||
# Qt6FooTargets.cmake. Once we can require CMake 3.26, we can simply link against
|
||||
# $<BUILD_LOCAL_INTERFACE:Qt6BarPrivate> in qt_internal_extend_target.
|
||||
#
|
||||
# For older CMake versions, we create an additional CMake file that's optionally included by
|
||||
# Qt6FooConfig.cmake to work around the lack of BUILD_LOCAL_INTERFACE.
|
||||
file(CONFIGURE
|
||||
OUTPUT "${arg_CONFIG_BUILD_DIR}/${package_name}-build.cmake"
|
||||
CONTENT "# This file marks this directory as part of Qt's build tree.
|
||||
set(__qt_${target}_always_load_private_module ON)
|
||||
"
|
||||
)
|
||||
endif()
|
||||
|
||||
configure_package_config_file(
|
||||
"${QT_CMAKE_DIR}/${module_config_input_file}"
|
||||
"${arg_CONFIG_BUILD_DIR}/${package_name}Config.cmake"
|
||||
|
@ -172,12 +172,16 @@ function(__qt_internal_walk_libs
|
||||
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()
|
||||
|
||||
set(lib_target "${lib}")
|
||||
|
||||
# Unwrap targets like $<LINK_ONLY:$<BUILD_INTERFACE:Qt6::CorePrivate>>
|
||||
while(lib_target
|
||||
MATCHES "^\\$<(LINK_ONLY|BUILD_INTERFACE|BUILD_LOCAL_INTERFACE):(.*)>$")
|
||||
set(lib_target ${CMAKE_MATCH_2})
|
||||
endwhile()
|
||||
|
||||
# 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.
|
||||
|
@ -148,6 +148,7 @@ function(qt_internal_extend_target target)
|
||||
|
||||
list(TRANSFORM arg_PUBLIC_LIBRARIES REPLACE "^Qt::" "${QT_CMAKE_EXPORT_NAMESPACE}::")
|
||||
list(TRANSFORM arg_LIBRARIES REPLACE "^Qt::" "${QT_CMAKE_EXPORT_NAMESPACE}::")
|
||||
qt_internal_wrap_private_modules(arg_LIBRARIES ${arg_LIBRARIES})
|
||||
|
||||
# Set-up the target
|
||||
|
||||
@ -257,6 +258,9 @@ function(qt_internal_extend_target target)
|
||||
if(TARGET "${target_private}")
|
||||
target_link_libraries("${target_private}"
|
||||
INTERFACE ${arg_PRIVATE_MODULE_INTERFACE})
|
||||
qt_internal_register_target_dependencies("${target_private}"
|
||||
PUBLIC ${arg_PRIVATE_MODULE_INTERFACE}
|
||||
)
|
||||
elseif(arg_PRIVATE_MODULE_INTERFACE)
|
||||
set(warning_message "")
|
||||
string(APPEND warning_message
|
||||
@ -268,9 +272,9 @@ function(qt_internal_extend_target target)
|
||||
endif()
|
||||
|
||||
set(qt_register_target_dependencies_args "")
|
||||
if(arg_PUBLIC_LIBRARIES OR arg_PRIVATE_MODULE_INTERFACE)
|
||||
if(arg_PUBLIC_LIBRARIES)
|
||||
list(APPEND qt_register_target_dependencies_args
|
||||
PUBLIC ${arg_PUBLIC_LIBRARIES} ${arg_PRIVATE_MODULE_INTERFACE})
|
||||
PUBLIC ${arg_PUBLIC_LIBRARIES})
|
||||
endif()
|
||||
if(qt_libs_private OR arg_LIBRARIES)
|
||||
list(APPEND qt_register_target_dependencies_args
|
||||
@ -337,6 +341,43 @@ function(qt_internal_extend_target target)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Takes an output variable and a list of libraries.
|
||||
#
|
||||
# Every library that is a private module is wrapped in $<BUILD_INTERFACE> or
|
||||
# $<BUILD_LOCAL_INTERFACE> if CMake is new enough.
|
||||
#
|
||||
# This is necessary for static builds, because if Qt6Foo links to Qt6BarPrivate, this link
|
||||
# dependency is purely internal. If we don't do this, CMake adds a target check for Qt6BarPrivate
|
||||
# in Qt6FooTargets.cmake. This breaks if Qt6BarPrivate is not find_package'ed before.
|
||||
function(qt_internal_wrap_private_modules out_var)
|
||||
set(result "")
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS "3.26")
|
||||
set(wrapper_genex "BUILD_INTERFACE")
|
||||
else()
|
||||
set(wrapper_genex "BUILD_LOCAL_INTERFACE")
|
||||
endif()
|
||||
|
||||
foreach(lib IN LISTS ARGN)
|
||||
if(TARGET "${lib}")
|
||||
get_target_property(lib_is_private_module ${lib} _qt_is_private_module)
|
||||
if(lib_is_private_module)
|
||||
# Add the public module as non-wrapped link dependency. This is necessary for
|
||||
# targets that link only to the private module. Consumers of this target would then
|
||||
# get a linker error about missing symbols from that Qt module.
|
||||
get_target_property(lib_public_module_target ${lib} _qt_public_module_target_name)
|
||||
list(APPEND result "${INSTALL_CMAKE_NAMESPACE}::${lib_public_module_target}")
|
||||
|
||||
# Wrap the private module in BUILD_LOCAL_INTERFACE.
|
||||
set(lib "$<${wrapper_genex}:${lib}>")
|
||||
endif()
|
||||
endif()
|
||||
list(APPEND result "${lib}")
|
||||
endforeach()
|
||||
|
||||
set("${out_var}" "${result}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Given CMAKE_CONFIG and ALL_CMAKE_CONFIGS, determines if a directory suffix needs to be appended
|
||||
# to each destination, and sets the computed install target destination arguments in OUT_VAR.
|
||||
# Defaults used for each of the destination types, and can be configured per destination type.
|
||||
|
@ -11,7 +11,7 @@ project(QtMockPlugins
|
||||
LANGUAGES CXX C
|
||||
)
|
||||
|
||||
find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals Core)
|
||||
find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals CorePrivate)
|
||||
qt_internal_project_setup()
|
||||
|
||||
find_package(Qt6 ${PROJECT_VERSION} QUIET CONFIG OPTIONAL_COMPONENTS Gui Widgets Xml)
|
||||
|
@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(test_private_includes)
|
||||
|
||||
find_package(Qt6Gui REQUIRED)
|
||||
find_package(Qt6GuiPrivate REQUIRED)
|
||||
|
||||
add_executable(testapp main.cpp)
|
||||
target_link_libraries(testapp PRIVATE Qt::GuiPrivate)
|
||||
|
@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(test_private_targets)
|
||||
|
||||
find_package(Qt6Gui REQUIRED)
|
||||
find_package(Qt6GuiPrivate REQUIRED)
|
||||
|
||||
add_executable(testapp main.cpp)
|
||||
target_link_libraries(testapp Qt::GuiPrivate)
|
||||
|
@ -22,7 +22,7 @@ project(tst_qaddpreroutine
|
||||
find_package(Qt6 COMPONENTS Core BuildInternals CONFIG REQUIRED)
|
||||
qt_prepare_standalone_project()
|
||||
|
||||
find_package(Qt6 COMPONENTS Gui Test CONFIG REQUIRED)
|
||||
find_package(Qt6 COMPONENTS GuiPrivate Test CONFIG REQUIRED)
|
||||
|
||||
qt_internal_add_plugin(QTBUG_90341ThemePlugin
|
||||
NO_UNITY_BUILD
|
||||
|
Loading…
x
Reference in New Issue
Block a user