From 54aeb4ccd77e5660474ae282d153c30fffda596e Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Mon, 19 Aug 2019 15:07:22 +0200 Subject: [PATCH] Add support for Qt header_modules aka a header only INTERFACE library Also add support for modules that have no private module counterpart. Both are needed for Designer's QtUiPlugin in qttools. Change-Id: Ia7e9d8837140e1de5cd59e196b4f63481ab68298 Reviewed-by: Tobias Hunger Reviewed-by: Qt CMake Build Bot --- cmake/QtBuild.cmake | 135 ++++++++++++++++++++++++++------------ cmake/QtPostProcess.cmake | 22 ++++++- util/cmake/pro2cmake.py | 4 ++ 3 files changed, 115 insertions(+), 46 deletions(-) diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake index 9a1573e0f4..53ed719430 100644 --- a/cmake/QtBuild.cmake +++ b/cmake/QtBuild.cmake @@ -383,7 +383,7 @@ endfunction() # Generates module .pri files for consumption by qmake function(qt_generate_module_pri_file target target_path pri_files_var) - set(flags INTERNAL_MODULE) + set(flags INTERNAL_MODULE HEADER_MODULE) set(options) set(multiopts QMAKE_MODULE_CONFIG) cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN}) @@ -391,10 +391,19 @@ function(qt_generate_module_pri_file target target_path pri_files_var) qt_internal_module_info(module "${target}") set(pri_files) - get_target_property(enabled_features "${target}" QT_ENABLED_PUBLIC_FEATURES) - get_target_property(disabled_features "${target}" QT_DISABLED_PUBLIC_FEATURES) - get_target_property(enabled_private_features "${target}" QT_ENABLED_PRIVATE_FEATURES) - get_target_property(disabled_private_features "${target}" QT_DISABLED_PRIVATE_FEATURES) + set(property_prefix) + if(arg_HEADER_MODULE) + set(property_prefix "interface_") + endif() + + get_target_property(enabled_features "${target}" + "${property_prefix}QT_ENABLED_PUBLIC_FEATURES") + get_target_property(disabled_features "${target}" + "${property_prefix}QT_DISABLED_PUBLIC_FEATURES") + get_target_property(enabled_private_features "${target}" + "${property_prefix}QT_ENABLED_PRIVATE_FEATURES") + get_target_property(disabled_private_features "${target}" + "${property_prefix}QT_DISABLED_PRIVATE_FEATURES") foreach(var enabled_features disabled_features enabled_private_features disabled_private_features) if(${var} STREQUAL "${var}-NOTFOUND") @@ -901,7 +910,7 @@ function(extend_target target) if (NOT TARGET "${target}") message(FATAL_ERROR "Trying to extend non-existing target \"${target}\".") endif() - qt_parse_all_arguments(arg "extend_target" "" "" + qt_parse_all_arguments(arg "extend_target" "HEADER_MODULE" "" "CONDITION;${__default_public_args};${__default_private_args};COMPILE_FLAGS" ${ARGN}) if ("x${arg_CONDITION}" STREQUAL x) set(arg_CONDITION ON) @@ -949,16 +958,35 @@ function(extend_target target) if (arg_COMPILE_FLAGS) set_source_files_properties(${arg_SOURCES} PROPERTIES COMPILE_FLAGS "${arg_COMPILE_FLAGS}") endif() - target_include_directories("${target}" PUBLIC ${arg_PUBLIC_INCLUDE_DIRECTORIES} PRIVATE ${arg_INCLUDE_DIRECTORIES}) - target_compile_definitions("${target}" PUBLIC ${arg_PUBLIC_DEFINES} PRIVATE ${arg_DEFINES}) - target_link_libraries("${target}" PUBLIC ${arg_PUBLIC_LIBRARIES} PRIVATE ${arg_LIBRARIES}) - target_compile_options("${target}" PUBLIC ${arg_PUBLIC_COMPILE_OPTIONS} PRIVATE ${arg_COMPILE_OPTIONS}) - target_link_options("${target}" PUBLIC ${arg_PUBLIC_LINK_OPTIONS} PRIVATE ${arg_LINK_OPTIONS}) - set_target_properties("${target}" PROPERTIES - AUTOMOC_MOC_OPTIONS "${arg_MOC_OPTIONS}" - _qt_target_deps "${target_deps}" - ) + set(public_visibility_option "PUBLIC") + set(private_visibility_option "PRIVATE") + if(arg_HEADER_MODULE) + set(public_visibility_option "INTERFACE") + set(private_visibility_option "INTERFACE") + endif() + target_include_directories("${target}" + ${public_visibility_option} ${arg_PUBLIC_INCLUDE_DIRECTORIES} + ${private_visibility_option} ${arg_INCLUDE_DIRECTORIES}) + target_compile_definitions("${target}" + ${public_visibility_option} ${arg_PUBLIC_DEFINES} + ${private_visibility_option} ${arg_DEFINES}) + target_link_libraries("${target}" + ${public_visibility_option} ${arg_PUBLIC_LIBRARIES} + ${private_visibility_option} ${arg_LIBRARIES}) + target_compile_options("${target}" + ${public_visibility_option} ${arg_PUBLIC_COMPILE_OPTIONS} + ${private_visibility_option} ${arg_COMPILE_OPTIONS}) + target_link_options("${target}" + ${public_visibility_option} ${arg_PUBLIC_LINK_OPTIONS} + ${private_visibility_option} ${arg_LINK_OPTIONS}) + + if(NOT arg_HEADER_MODULE) + set_target_properties("${target}" PROPERTIES + AUTOMOC_MOC_OPTIONS "${arg_MOC_OPTIONS}" + _qt_target_deps "${target_deps}" + ) + endif() # When computing the private library dependencies, we need to check not only the known # modules added by this repo's qt_build_repo(), but also all module dependencies that @@ -1172,7 +1200,7 @@ function(add_qt_module target) # Process arguments: qt_parse_all_arguments(arg "add_qt_module" - "NO_MODULE_HEADERS;STATIC;DISABLE_TOOLS_EXPORT;EXCEPTIONS;INTERNAL_MODULE;NO_SYNC_QT" + "NO_MODULE_HEADERS;STATIC;DISABLE_TOOLS_EXPORT;EXCEPTIONS;INTERNAL_MODULE;NO_SYNC_QT;NO_PRIVATE_MODULE;HEADER_MODULE" "CONFIG_MODULE_NAME" "${__default_private_args};${__default_public_args};QMAKE_MODULE_CONFIG;EXTRA_CMAKE_FILES;EXTRA_CMAKE_INCLUDES" ${ARGN}) @@ -1183,7 +1211,9 @@ function(add_qt_module target) qt_internal_add_qt_repo_known_module("${target}") ### Define Targets: - if(${arg_STATIC}) + if(${arg_HEADER_MODULE}) + add_library("${target}" INTERFACE) + elseif(${arg_STATIC}) add_library("${target}" STATIC) elseif(${QT_BUILD_SHARED_LIBS}) add_library("${target}" SHARED) @@ -1193,13 +1223,15 @@ function(add_qt_module target) qt_internal_add_target_aliases("${target}") # Add _private target to link against the private headers: - set(target_private "${target}Private") - add_library("${target_private}" INTERFACE) - qt_internal_add_target_aliases("${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}") + endif() # Module headers: if(${arg_NO_MODULE_HEADERS} OR ${arg_NO_SYNC_QT}) - set_target_properties("${target}" PROPERTIES MODULE_HAS_HEADERS OFF) + set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_HAS_HEADERS OFF) else() # Use QT_BUILD_DIR for the syncqt call. # So we either write the generated files into the qtbase non-prefix build root, or the @@ -1215,7 +1247,7 @@ function(add_qt_module target) "${PROJECT_SOURCE_DIR}") execute_process(COMMAND ${syncqt_full_command}) - set_target_properties("${target}" PROPERTIES MODULE_HAS_HEADERS ON) + set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_HAS_HEADERS ON) ### FIXME: Can we replace headers.pri? qt_read_headers_pri("${target}" "module_headers") @@ -1227,25 +1259,29 @@ function(add_qt_module target) endif() endif() - # Plugin types associated to a module - if(NOT "x${arg_PLUGIN_TYPES}" STREQUAL "x") - set_target_properties("${target}" PROPERTIES MODULE_PLUGIN_TYPES "${arg_PLUGIN_TYPES}") - endif() + if(NOT arg_HEADER_MODULE) + # Plugin types associated to a module + if(NOT "x${arg_PLUGIN_TYPES}" STREQUAL "x") + set_target_properties("${target}" PROPERTIES MODULE_PLUGIN_TYPES "${arg_PLUGIN_TYPES}") + endif() - set_target_properties("${target}" PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" - RUNTIME_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}" - RUNTIME_OUTPUT_DIRECTORY_RELEASE "${QT_BUILD_DIR}/${INSTALL_BINDIR}" - RUNTIME_OUTPUT_DIRECTORY_DEBUG "${QT_BUILD_DIR}/${INSTALL_BINDIR}" - ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} - OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${target}" - ) + set_target_properties("${target}" PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" + RUNTIME_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${QT_BUILD_DIR}/${INSTALL_BINDIR}" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${QT_BUILD_DIR}/${INSTALL_BINDIR}" + ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${target}" + ) + endif() qt_internal_library_deprecation_level(deprecation_define) - qt_autogen_tools_initial_setup(${target}) + if(NOT arg_HEADER_MODULE) + qt_autogen_tools_initial_setup(${target}) + endif() set(private_includes "${CMAKE_CURRENT_SOURCE_DIR}" @@ -1267,7 +1303,13 @@ function(add_qt_module target) endif() list(APPEND public_includes ${arg_PUBLIC_INCLUDE_DIRECTORIES}) + set(header_module) + if(arg_HEADER_MODULE) + set(header_module "HEADER_MODULE") + endif() + extend_target("${target}" + ${header_module} SOURCES ${arg_SOURCES} INCLUDE_DIRECTORIES ${private_includes} @@ -1301,7 +1343,7 @@ function(add_qt_module target) DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} ) - if(NOT ${arg_EXCEPTIONS}) + if(NOT ${arg_EXCEPTIONS} AND NOT ${arg_HEADER_MODULE}) qt_internal_set_no_exceptions_flags("${target}") endif() @@ -1399,7 +1441,10 @@ set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})") ) file(COPY ${extra_cmake_files} DESTINATION "${config_build_dir}") - set(exported_targets ${target} ${target_private}) + set(exported_targets ${target}) + if(NOT ${arg_NO_PRIVATE_MODULE}) + list(APPEND exported_targets ${target_private}) + endif() set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets") qt_install(TARGETS ${exported_targets} EXPORT ${export_name} @@ -1435,6 +1480,7 @@ set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})") qt_path_join(pri_target_path ${PROJECT_BINARY_DIR} mkspecs/modules) qt_generate_module_pri_file("${target}" "${pri_target_path}" module_pri_files ${arg_INTERNAL_MODULE} + ${header_module} QMAKE_MODULE_CONFIG ${arg_QMAKE_MODULE_CONFIG} ) @@ -1442,7 +1488,9 @@ set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})") ### fixme: cmake is missing a built-in variable for this. We want to apply it only to modules and plugins # that belong to Qt. - qt_internal_add_link_flags_no_undefined("${target}") + if(NOT arg_HEADER_MODULE) + qt_internal_add_link_flags_no_undefined("${target}") + endif() set(interface_includes "$" @@ -1457,9 +1505,10 @@ set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})") ) endif() - target_include_directories("${target_private}" INTERFACE - ${interface_includes} - ) + + if(NOT ${arg_NO_PRIVATE_MODULE}) + target_include_directories("${target_private}" INTERFACE ${interface_includes}) + endif() if(NOT ${arg_DISABLE_TOOLS_EXPORT}) qt_export_tools(${target}) diff --git a/cmake/QtPostProcess.cmake b/cmake/QtPostProcess.cmake index f91fdaef63..8a09efe35a 100644 --- a/cmake/QtPostProcess.cmake +++ b/cmake/QtPostProcess.cmake @@ -54,7 +54,16 @@ macro(qt_collect_third_party_deps) endmacro() function(qt_internal_create_module_depends_file target) - get_target_property(depends "${target}" LINK_LIBRARIES) + get_target_property(target_type "${target}" TYPE) + if(target_type STREQUAL "INTERFACE_LIBRARY") + set(arg_HEADER_MODULE ON) + else() + set(arg_HEADER_MODULE OFF) + endif() + + if(NOT arg_HEADER_MODULE) + get_target_property(depends "${target}" LINK_LIBRARIES) + endif() get_target_property(public_depends "${target}" INTERFACE_LINK_LIBRARIES) # Used for collecting Qt module dependencies that should be find_package()'d in @@ -62,7 +71,9 @@ function(qt_internal_create_module_depends_file target) get_target_property(target_deps "${target}" _qt_target_deps) set(target_deps_seen "") - get_target_property(extra_depends "${target}" QT_EXTRA_PACKAGE_DEPENDENCIES) + if(NOT arg_HEADER_MODULE) + get_target_property(extra_depends "${target}" QT_EXTRA_PACKAGE_DEPENDENCIES) + endif() if(NOT extra_depends STREQUAL "${extra_depends}-NOTFOUND") list(APPEND target_deps ${extra_depends}) endif() @@ -140,7 +151,7 @@ function(qt_internal_create_module_depends_file target) list(REMOVE_DUPLICATES qtdeps) endif() - get_target_property(hasModuleHeaders "${target}" MODULE_HAS_HEADERS) + get_target_property(hasModuleHeaders "${target}" INTERFACE_MODULE_HAS_HEADERS) if (${hasModuleHeaders}) qt_internal_write_depends_file("${target}" ${qtdeps}) endif() @@ -260,6 +271,11 @@ function(qt_internal_create_plugins_files) message("Generating Plugins files for ${repo_known_modules}...") foreach (QT_MODULE ${repo_known_modules}) + get_target_property(target_type "${QT_MODULE}" TYPE) + if(target_type STREQUAL "INTERFACE_LIBRARY") + # No plugins are provided by a header only module. + continue() + endif() qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${INSTALL_CMAKE_NAMESPACE}${QT_MODULE}) qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${INSTALL_CMAKE_NAMESPACE}${QT_MODULE}) set(QT_MODULE_PLUGIN_INCLUDES "") diff --git a/util/cmake/pro2cmake.py b/util/cmake/pro2cmake.py index 8c805ea481..1d30cac4b6 100755 --- a/util/cmake/pro2cmake.py +++ b/util/cmake/pro2cmake.py @@ -1962,6 +1962,10 @@ def write_module(cm_fh: typing.IO[str], scope: Scope, *, extra.append('NO_MODULE_HEADERS') if 'minimal_syncqt' in scope.get('CONFIG'): extra.append('NO_SYNC_QT') + if 'no_private_module' in scope.get('CONFIG'): + extra.append('NO_PRIVATE_MODULE') + if 'header_module' in scope.get('CONFIG'): + extra.append('HEADER_MODULE') module_config = scope.get("MODULE_CONFIG") if len(module_config):