diff --git a/cmake/QtFindPackageHelpers.cmake b/cmake/QtFindPackageHelpers.cmake index 85dc1ff7db8..5bfc0ff4f65 100644 --- a/cmake/QtFindPackageHelpers.cmake +++ b/cmake/QtFindPackageHelpers.cmake @@ -254,7 +254,7 @@ function(qt_record_extra_qt_main_tools_package_dependency main_target_name "${main_target_name}" "${qtfied_package_name_versioned}" "${dep_package_version}") endfunction() -# This function stores the list of Qt modules a library depend on, +# This function stores the list of Qt targets a library depend on, # along with their version info, for usage in ${target}Depends.cmake file function(qt_register_target_dependencies target public_libs private_libs) get_target_property(target_deps "${target}" _qt_target_deps) @@ -272,15 +272,13 @@ function(qt_register_target_dependencies target public_libs private_libs) foreach(lib IN LISTS lib_list) if ("${lib}" MATCHES "^Qt::(.*)") set(lib "${CMAKE_MATCH_1}") - if (lib STREQUAL Platform - OR lib STREQUAL GlobalConfig - OR lib STREQUAL GlobalConfigPrivate - OR lib STREQUAL PlatformModuleInternal - OR lib STREQUAL PlatformPluginInternal - OR lib STREQUAL PlatformToolInternal) + if (lib STREQUAL "Platform" + OR lib STREQUAL "GlobalConfig" + OR lib STREQUAL "GlobalConfigPrivate" + OR lib STREQUAL "PlatformModuleInternal" + OR lib STREQUAL "PlatformPluginInternal" + OR lib STREQUAL "PlatformToolInternal") list(APPEND target_deps "Qt6\;${PROJECT_VERSION}") - elseif ("${lib}" MATCHES "(.*)Private") - list(APPEND target_deps "${INSTALL_CMAKE_NAMESPACE}${CMAKE_MATCH_1}\;${PROJECT_VERSION}") else() list(APPEND target_deps "${INSTALL_CMAKE_NAMESPACE}${lib}\;${PROJECT_VERSION}") endif() diff --git a/cmake/QtFrameworkHelpers.cmake b/cmake/QtFrameworkHelpers.cmake index 6289ce98b14..59555522e42 100644 --- a/cmake/QtFrameworkHelpers.cmake +++ b/cmake/QtFrameworkHelpers.cmake @@ -69,10 +69,18 @@ function(qt_copy_framework_headers target) get_target_property(fw_dir ${target} LIBRARY_OUTPUT_DIRECTORY) get_target_property(fw_name ${target} OUTPUT_NAME) set(fw_headers_dir ${fw_dir}/${fw_name}.framework/Versions/${fw_version}/Headers/) + + # The module name might be different of the actual target name. + get_target_property(module_interface_name ${target} _qt_module_interface_name) + if(module_interface_name) + set(module "Qt${module_interface_name}") + else() + set(module "Qt${target}") + endif() if(ARG_PRIVATE) - string(APPEND fw_headers_dir "${fw_bundle_version}/Qt${target}/private/") + string(APPEND fw_headers_dir "${fw_bundle_version}/${module}/private/") elseif(ARG_QPA) - string(APPEND fw_headers_dir "${fw_bundle_version}/Qt${target}/qpa/") + string(APPEND fw_headers_dir "${fw_bundle_version}/${module}/qpa/") endif() set(out_files) diff --git a/cmake/QtModuleDependencies.cmake.in b/cmake/QtModuleDependencies.cmake.in index 5ec9345209e..e9159a20d28 100644 --- a/cmake/QtModuleDependencies.cmake.in +++ b/cmake/QtModuleDependencies.cmake.in @@ -81,14 +81,23 @@ if(NOT "${QT_HOST_PATH}" STREQUAL "") set(CMAKE_FIND_ROOT_PATH ${BACKUP_@target@_CMAKE_FIND_ROOT_PATH}) endif() +# TODO: The dependencies lookup mechanism is common for Modules and Plugins. +# It should be moved to the common public helper file. +# # note: target_deps example: "Qt6Core\;5.12.0;Qt6Gui\;5.12.0" set(_target_deps "@target_deps@") foreach(_target_dep ${_target_deps}) list(GET _target_dep 0 pkg) list(GET _target_dep 1 version) - if (NOT ${pkg}_FOUND) + if(NOT ${pkg}_FOUND) + set(pkg_names ${pkg}) + if(pkg MATCHES "(.*)Private$") + set(pkg_names "${CMAKE_MATCH_1};${pkg}") + endif() find_dependency(${pkg} ${version} + NAMES + ${pkg_names} PATHS "${CMAKE_CURRENT_LIST_DIR}/.." ${_qt_additional_packages_prefix_path} diff --git a/cmake/QtModuleHelpers.cmake b/cmake/QtModuleHelpers.cmake index 4d976173dff..e53843dc92c 100644 --- a/cmake/QtModuleHelpers.cmake +++ b/cmake/QtModuleHelpers.cmake @@ -16,6 +16,7 @@ macro(qt_internal_get_internal_add_module_keywords option_args single_args multi ) set(${single_args} MODULE_INCLUDE_NAME + MODULE_INTERFACE_NAME CONFIG_MODULE_NAME PRECOMPILED_HEADER CONFIGURE_FILE_PATH @@ -48,9 +49,16 @@ endmacro() # Don't generate a Qt6*AdditionalTargetInfo.cmake file. # The caller is responsible for creating one. # +# MODULE_INTERFACE_NAME +# The custom name of the module interface. This name is used as a part of the include paths +# associated with the module and other interface names. The default value is the target name. +# If the INTERNAL_MODULE option is specified, MODULE_INTERFACE_NAME is not specified and the +# target name ends with the suffix 'Private', the MODULE_INTERFACE_NAME value defaults to the +# non-suffixed target name, e.g.: +# For the SomeInternalModulePrivate target, the MODULE_INTERFACE_NAME will be +# SomeInternalModule +# function(qt_internal_add_module target) - qt_internal_module_info(module "${target}") - qt_internal_get_internal_add_module_keywords( option_args single_args @@ -64,16 +72,25 @@ function(qt_internal_add_module target) ${ARGN} ) - qt_internal_add_qt_repo_known_module("${target}") - - if(NOT DEFINED arg_CONFIG_MODULE_NAME) - set(arg_CONFIG_MODULE_NAME "${module_lower}") + if(arg_INTERNAL_MODULE) + set(arg_INTERNAL_MODULE "INTERNAL_MODULE") + set(arg_NO_PRIVATE_MODULE TRUE) + # Assume the interface name of the internal module should be the module name without the + # 'Private' suffix. + if(NOT arg_MODULE_INTERFACE_NAME) + if(target MATCHES "(.*)Private$") + set(arg_MODULE_INTERFACE_NAME "${CMAKE_MATCH_1}") + else() + message(WARNING "The internal module target should end with the 'Private' suffix.") + endif() + endif() + else() + unset(arg_INTERNAL_MODULE) endif() - # Module define needs to take into account the config module name. - string(TOUPPER "${arg_CONFIG_MODULE_NAME}" module_define_infix) - string(REPLACE "-" "_" module_define_infix "${module_define_infix}") - string(REPLACE "." "_" module_define_infix "${module_define_infix}") + if(NOT arg_MODULE_INTERFACE_NAME) + set(arg_MODULE_INTERFACE_NAME "${target}") + endif() ### Define Targets: set(is_interface_lib 0) @@ -93,6 +110,23 @@ function(qt_internal_add_module target) set(is_static_lib 1) endif() + set_target_properties(${target} PROPERTIES + _qt_module_interface_name "${arg_MODULE_INTERFACE_NAME}" + ) + set_property(TARGET ${target} APPEND PROPERTY EXPORT_PROPERTIES _qt_module_interface_name) + + qt_internal_module_info(module "${target}") + qt_internal_add_qt_repo_known_module("${target}") + + if(NOT arg_CONFIG_MODULE_NAME) + set(arg_CONFIG_MODULE_NAME "${module_lower}") + endif() + + # Module define needs to take into account the config module name. + string(TOUPPER "${arg_CONFIG_MODULE_NAME}" module_define_infix) + string(REPLACE "-" "_" module_define_infix "${module_define_infix}") + string(REPLACE "." "_" module_define_infix "${module_define_infix}") + set(property_prefix "INTERFACE_") if(NOT arg_HEADER_MODULE) qt_set_common_target_properties(${target}) @@ -144,15 +178,30 @@ function(qt_internal_add_module target) qt_skip_warnings_are_errors_when_repo_unclean("${target}") _qt_internal_apply_strict_cpp("${target}") + # No need to compile Q_IMPORT_PLUGIN-containing files for non-executables. + if(is_static_lib) + _qt_internal_disable_static_default_plugins("${target}") + endif() + # Add _private target to link against the private headers: + set(target_private "${target}Private") if(NOT ${arg_NO_PRIVATE_MODULE}) - set(target_private "${target}Private") add_library("${target_private}" INTERFACE) qt_internal_add_target_aliases("${target_private}") set_target_properties(${target_private} PROPERTIES _qt_config_module_name ${arg_CONFIG_MODULE_NAME}_private) set_property(TARGET "${target_private}" APPEND PROPERTY EXPORT_PROPERTIES _qt_config_module_name) + elseif(arg_INTERNAL_MODULE) + # TODO: We need to create temporary alias targets for the internal modules to keep the + # existing code compatible to the internal modules that don't have the 'Private' suffix yet. + # Remove this once the migration is complete. + set(versionless_private_alias "Qt::${target_private}") + set(versionfull_private_alias "Qt${PROJECT_VERSION_MAJOR}::${target_private}") + add_library("${versionless_private_alias}" ALIAS "${target}") + add_library("${versionfull_private_alias}" ALIAS "${target}") + unset(versionless_private_alias) + unset(versionfull_private_alias) endif() if(NOT arg_HEADER_MODULE) @@ -620,12 +669,6 @@ set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})") EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target} CONFIG_INSTALL_DIR "${config_install_dir}") - if (${arg_INTERNAL_MODULE}) - set(arg_INTERNAL_MODULE "INTERNAL_MODULE") - else() - unset(arg_INTERNAL_MODULE) - endif() - ### fixme: cmake is missing a built-in variable for this. We want to apply it only to modules and plugins # that belong to Qt. if(NOT arg_HEADER_MODULE) @@ -671,7 +714,9 @@ set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})") "${module_headers_clean}") endif() - if(NOT ${arg_NO_PRIVATE_MODULE}) + if(arg_INTERNAL_MODULE) + target_include_directories("${target}" INTERFACE ${interface_includes}) + elseif(NOT ${arg_NO_PRIVATE_MODULE}) target_include_directories("${target_private}" INTERFACE ${interface_includes}) target_link_libraries("${target_private}" INTERFACE "${target}") endif() @@ -706,7 +751,7 @@ function(qt_finalize_module target) qt_generate_module_pri_file("${target}" ${ARGN}) endfunction() -# Get a set of Qt module related values based on the target name. +# Get a set of Qt module related values based on the target. # When doing qt_internal_module_info(foo Core) this method will set # the following variables in the caller's scope: # * foo with the value "QtCore" @@ -720,11 +765,16 @@ endfunction() # e.g for QtQuick it would be qtdeclarative_build_dir/include/QtQuick for a prefix build or # qtbase_build_dir/include/QtQuick for a non-prefix build function(qt_internal_module_info result target) - set(module "Qt${target}") + get_target_property(module_interface_name ${target} _qt_module_interface_name) + if(NOT module_interface_name) + message(FATAL_ERROR "${target} is not a module.") + endif() + + qt_internal_qtfy_target(module ${module_interface_name}) set("${result}" "${module}" PARENT_SCOPE) - set("${result}_versioned" "Qt${PROJECT_VERSION_MAJOR}${target}" PARENT_SCOPE) - string(TOUPPER "${target}" upper) - string(TOLOWER "${target}" lower)# * foo_upper with the value "CORE" + set("${result}_versioned" "${module_versioned}" PARENT_SCOPE) + string(TOUPPER "${module_interface_name}" upper) + string(TOLOWER "${module_interface_name}" lower)# * foo_upper with the value "CORE" set("${result}_upper" "${upper}" PARENT_SCOPE) set("${result}_lower" "${lower}" PARENT_SCOPE) set("${result}_repo_include_dir" "${QT_BUILD_DIR}/include" PARENT_SCOPE) diff --git a/cmake/QtPluginDependencies.cmake.in b/cmake/QtPluginDependencies.cmake.in index 7bd1eef9aa9..f64cc77714f 100644 --- a/cmake/QtPluginDependencies.cmake.in +++ b/cmake/QtPluginDependencies.cmake.in @@ -32,6 +32,9 @@ if(QT_DISABLE_NO_DEFAULT_PATH_IN_QT_PACKAGES) set(__qt_use_no_default_path_for_qt_packages "") endif() +# TODO: The dependencies lookup mechanism is common for Modules and Plugins. +# It should be moved to the common public helper file. +# # note: target_deps example: "Qt6Core\;5.12.0;Qt6Gui\;5.12.0" set(_target_deps "@target_deps@") foreach(_target_dep ${_target_deps}) @@ -39,7 +42,13 @@ foreach(_target_dep ${_target_deps}) list(GET _target_dep 1 version) if (NOT ${pkg}_FOUND) + set(pkg_names ${pkg}) + if(pkg MATCHES "(.*)Private$") + set(pkg_names "${CMAKE_MATCH_1};${pkg}") + endif() find_dependency(${pkg} ${version} + NAMES + ${pkg_names} PATHS @find_dependency_paths@ ${_qt_additional_packages_prefix_path} diff --git a/cmake/QtPostProcessHelpers.cmake b/cmake/QtPostProcessHelpers.cmake index c8d310d93dd..9307ea8a207 100644 --- a/cmake/QtPostProcessHelpers.cmake +++ b/cmake/QtPostProcessHelpers.cmake @@ -3,7 +3,7 @@ function(qt_internal_write_depends_file module) set(contents "/* This file was generated by cmake with the info from ${module} target. */\n") string(APPEND contents "#ifdef __cplusplus /* create empty PCH in C mode */\n") foreach (m ${ARGN}) - string(APPEND contents "# include \n") + string(APPEND contents "# include <${m}/${m}>\n") endforeach() string(APPEND contents "#endif\n") @@ -64,6 +64,41 @@ macro(qt_collect_third_party_deps target) endforeach() endmacro() +# Filter the dependency targets to collect unique set of the dependencies. +# non-Private and Private targets are treated as the single object in this context +# since they are defined by the same CMake package. For internal modules +# the CMake package will be always Private. +function(qt_internal_remove_qt_dependency_duplicates out_deps deps) + set(${out_deps} "") + foreach(dep ${deps}) + if(dep) + list(FIND ${out_deps} "${dep}" dep_seen) + + # If the library depends on the Private and non-Private targets, + # we only need to 'find_dependency' for one of them. + if(dep_seen EQUAL -1 AND "${dep}" MATCHES "(.+)Private\;(.+)") + list(FIND ${out_deps} "${CMAKE_MATCH_1};${CMAKE_MATCH_2}" dep_seen) + endif() + if(dep_seen EQUAL -1) + list(LENGTH dep len) + if(NOT (len EQUAL 2)) + message(FATAL_ERROR "List '${dep}' should look like QtFoo;version") + endif() + list(GET dep 0 dep_name) + list(GET dep 1 dep_ver) + + # Skip over Qt6 dependency, because we will manually handle it in the Dependencies + # file before everything else, to ensure that find_package(Qt6Core)-style works. + if(dep_name STREQUAL "${INSTALL_CMAKE_NAMESPACE}") + continue() + endif() + list(APPEND ${out_deps} "${dep_name}\;${dep_ver}") + endif() + endif() + endforeach() + set(${out_deps} "${${out_deps}}" PARENT_SCOPE) +endfunction() + function(qt_internal_create_module_depends_file target) get_target_property(target_type "${target}" TYPE) if(target_type STREQUAL "INTERFACE_LIBRARY") @@ -93,7 +128,7 @@ function(qt_internal_create_module_depends_file target) if(NOT arg_HEADER_MODULE) get_target_property(extra_depends "${target}" QT_EXTRA_PACKAGE_DEPENDENCIES) endif() - if(NOT extra_depends STREQUAL "${extra_depends}-NOTFOUND") + if(NOT extra_depends MATCHES "-NOTFOUND$") list(APPEND target_deps "${extra_depends}") endif() @@ -152,13 +187,11 @@ function(qt_internal_create_module_depends_file target) endif() endif() endif() - if (dep MATCHES "(.*)Private") - set(dep "${CMAKE_MATCH_1}") - endif() list(FIND known_modules "${dep}" _pos) if (_pos GREATER -1) - list(APPEND qtdeps "${dep}") + qt_internal_module_info(module ${QT_CMAKE_EXPORT_NAMESPACE}::${dep}) + list(APPEND qtdeps ${module}) # Make the ModuleTool package depend on dep's ModuleTool package. list(FIND tool_deps_seen ${dep} dep_seen) @@ -178,33 +211,16 @@ function(qt_internal_create_module_depends_file target) "${INSTALL_CMAKE_NAMESPACE}${target}Tools\;${PROJECT_VERSION}") endif() - # Dirty deduplication hack because of https://gitlab.kitware.com/cmake/cmake/issues/19200 foreach(dep ${target_deps}) - if(dep) - list(FIND target_deps_seen "${dep}" dep_seen) - if(dep_seen EQUAL -1) - list(LENGTH dep len) - if(NOT (len EQUAL 2)) - message(FATAL_ERROR "List '${dep}' should look like QtFoo;version") - endif() - list(GET dep 0 dep_name) - list(GET dep 1 dep_ver) - - # Skip over Qt6 dependency, because we will manually handle it in the Dependencies - # file before everything else, to ensure that find_package(Qt6Core)-style works. - if(dep_name STREQUAL INSTALL_CMAKE_NAMESPACE) - continue() - endif() - - list(APPEND target_deps_seen "${dep_name}\;${dep_ver}") - - if (dep_name MATCHES "${INSTALL_CMAKE_NAMESPACE}(.*)") - list(APPEND qt_module_dependencies "${CMAKE_MATCH_1}") - endif() - endif() + if(NOT dep MATCHES ".+Private$" AND + dep MATCHES "${INSTALL_CMAKE_NAMESPACE}(.+)") + list(APPEND qt_module_dependencies "${CMAKE_MATCH_1}") endif() endforeach() - set(target_deps "${target_deps_seen}") + list(REMOVE_DUPLICATES qt_module_dependencies) + + qt_internal_remove_qt_dependency_duplicates(target_deps "${target_deps}") + if (DEFINED qtdeps) list(REMOVE_DUPLICATES qtdeps) @@ -251,23 +267,7 @@ function(qt_internal_create_plugin_depends_file target) qt_collect_third_party_deps(${target}) - # Dirty hack because https://gitlab.kitware.com/cmake/cmake/issues/19200 - foreach(dep ${target_deps}) - if(dep) - list(FIND target_deps_seen "${dep}" dep_seen) - if(dep_seen EQUAL -1) - list(LENGTH dep len) - if(NOT (len EQUAL 2)) - message(FATAL_ERROR "List '${dep}' should look like QtFoo;version") - endif() - list(GET dep 0 dep_name) - list(GET dep 1 dep_ver) - - list(APPEND target_deps_seen "${dep_name}\;${dep_ver}") - endif() - endif() - endforeach() - set(target_deps "${target_deps_seen}") + qt_internal_remove_qt_dependency_duplicates(target_deps "${target_deps}") if(third_party_deps OR target_deps) # Setup build and install paths diff --git a/cmake/QtSyncQtHelpers.cmake b/cmake/QtSyncQtHelpers.cmake index 2014405017e..9e968cd0f31 100644 --- a/cmake/QtSyncQtHelpers.cmake +++ b/cmake/QtSyncQtHelpers.cmake @@ -40,7 +40,7 @@ endfunction() function(qt_install_injections target build_dir install_dir) set(injections ${ARGN}) - set(module "Qt${target}") + qt_internal_module_info(module ${target}) get_target_property(target_type ${target} TYPE) if (target_type STREQUAL "INTERFACE_LIBRARY") set(is_framework FALSE)