From 572c03eb7a583baf1f48e5144d2868e5588d292a Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Tue, 11 Feb 2020 15:38:47 +0100 Subject: [PATCH] Add support for qt_helper_lib() Add qt_add_3rdparty_library() function as a replacement for qmake's qt_helper_lib feature. All 3rdparty libraries will be available under the Qt:: alias when built through this method so that they can properly register as dependencies of a Qt module. This patch also adds Qt3rdPartyLibraryConfig.cmake.in to export the CMake configuration for static builds and shared libraries. Change-Id: I52bf3a95ca22fccd9ab54343468847bb1b570c28 Fixes: QTBUG-81969 Reviewed-by: Liang Qi Reviewed-by: Alexandru Croitor --- cmake/Qt3rdPartyLibraryConfig.cmake.in | 26 +++++ cmake/QtBuild.cmake | 136 +++++++++++++++++++++++++ util/cmake/pro2cmake.py | 39 +++++++ 3 files changed, 201 insertions(+) create mode 100644 cmake/Qt3rdPartyLibraryConfig.cmake.in diff --git a/cmake/Qt3rdPartyLibraryConfig.cmake.in b/cmake/Qt3rdPartyLibraryConfig.cmake.in new file mode 100644 index 0000000000..0facce906f --- /dev/null +++ b/cmake/Qt3rdPartyLibraryConfig.cmake.in @@ -0,0 +1,26 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) + +get_filename_component(_import_prefix "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_import_prefix "${_import_prefix}" REALPATH) + +# Extra cmake code begin +@extra_cmake_code@ +# Extra cmake code end + +# Find required dependencies, if any. +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Dependencies.cmake") + include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Dependencies.cmake") +endif() + +if (NOT QT_NO_CREATE_TARGETS) + include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Targets.cmake") + if(NOT QT_NO_CREATE_VERSIONLESS_TARGETS) + include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@VersionlessTargets.cmake") + endif() +endif() + +foreach(extra_cmake_include @extra_cmake_includes@) + include("${CMAKE_CURRENT_LIST_DIR}/${extra_cmake_include}") +endforeach() diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake index 08bc66b358..d2d43b7910 100644 --- a/cmake/QtBuild.cmake +++ b/cmake/QtBuild.cmake @@ -2936,6 +2936,142 @@ function(qt_add_cmake_library target) endfunction() +# +# This function replaces qmake's qt_helper_lib feature. It is intended to +# compile 3rdparty libraries as part of the build. +# +function(qt_add_3rdparty_library target) + # Process arguments: + qt_parse_all_arguments(arg "qt_add_3rdparty_library" + "SHARED;MODULE;STATIC;INTERFACE;EXCEPTIONS" + "OUTPUT_DIRECTORY" + "${__default_private_args};${__default_public_args}" + ${ARGN} + ) + + ### Define Targets: + if(${arg_INTERFACE}) + add_library("${target}" INTERFACE) + elseif(${arg_STATIC} OR (${arg_MODULE} AND NOT BUILD_SHARED_LIBS)) + add_library("${target}" STATIC) + elseif(${arg_SHARED}) + add_library("${target}" SHARED) + elseif(${arg_MODULE}) + add_library("${target}" MODULE) + set_property(TARGET ${name} PROPERTY C_VISIBILITY_PRESET default) + set_property(TARGET ${name} PROPERTY CXX_VISIBILITY_PRESET default) + + if(APPLE) + # CMake defaults to using .so extensions for loadable modules, aka plugins, + # but Qt plugins are actually suffixed with .dylib. + set_property(TARGET "${target}" PROPERTY SUFFIX ".dylib") + endif() + else() + add_library("${target}") + endif() + + if (NOT arg_ARCHIVE_INSTALL_DIRECTORY AND arg_INSTALL_DIRECTORY) + set(arg_ARCHIVE_INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}") + endif() + + qt_internal_add_qt_repo_known_module(${target}) + qt_internal_add_target_aliases(${target}) + + if (ANDROID) + qt_android_apply_arch_suffix("${target}") + endif() + + qt_skip_warnings_are_errors_when_repo_unclean("${target}") + + if(NOT arg_HEADER_MODULE) + set_target_properties(${target} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" + RUNTIME_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}" + ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + QT_MODULE_IS_3RDPARTY_LIBRARY TRUE + ) + qt_handle_multi_config_output_dirs("${target}") + + set_target_properties(${target} PROPERTIES + OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${target}" + ) + endif() + + if(NOT arg_INTERFACE) + # This property is used for super builds with static libraries. We use + # it in QtPlugins.cmake.in to avoid "polluting" the dependency chain + # for the target in it's project directory. + # E.g: When we process find_package(Qt6 ... Gui) in QtDeclarative, the + # rules in QtPugins.cmake add all the known Gui plugins as interface + # dependencies. This in turn causes circular dependencies on every + # plugin which links against Gui. Plugin A -> GUI -> Plugin A .... + set_target_properties(${target} PROPERTIES QT_BUILD_PROJECT_NAME ${PROJECT_NAME}) + endif() + + if(NOT arg_EXCEPTIONS AND NOT arg_INTERFACE) + qt_internal_set_no_exceptions_flags("${target}") + endif() + + qt_extend_target("${target}" + SOURCES ${arg_SOURCES} + INCLUDE_DIRECTORIES + ${arg_INCLUDE_DIRECTORIES} + PUBLIC_INCLUDE_DIRECTORIES + ${arg_PUBLIC_INCLUDE_DIRECTORIES} + PUBLIC_DEFINES + ${arg_PUBLIC_DEFINES} + DEFINES + ${arg_DEFINES} + PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES} + LIBRARIES ${arg_LIBRARIES} + COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} + PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS} + LINK_OPTIONS ${arg_LINK_OPTIONS} + PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS} + MOC_OPTIONS ${arg_MOC_OPTIONS} + ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + ${install_arguments} + ) + + if(NOT BUILD_SHARED_LIBS OR arg_SHARED) + set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}") + qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix}) + qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix}) + set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets") + + configure_package_config_file( + "${QT_CMAKE_DIR}/Qt3rdPartyLibraryConfig.cmake.in" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" + INSTALL_DESTINATION "${config_install_dir}" + ) + + write_basic_package_version_file( + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion + ) + + qt_install(TARGETS ${target} + EXPORT "${export_name}" + DESTINATION "${config_install_dir}" + ) + + qt_install(EXPORT ${export_name} + NAMESPACE "${QT_CMAKE_EXPORT_NAMESPACE}::" + DESTINATION "${config_install_dir}" + ) + + qt_internal_export_modern_cmake_config_targets_file( + TARGETS ${target} + EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target} + CONFIG_INSTALL_DIR "${config_install_dir}" + ) + endif() +endfunction() + function(qt_get_tool_cmake_configuration out_var) qt_get_main_cmake_configuration("${out_var}") string(TOUPPER "${${out_var}}" upper_config) diff --git a/util/cmake/pro2cmake.py b/util/cmake/pro2cmake.py index a93c506169..709ab01c39 100755 --- a/util/cmake/pro2cmake.py +++ b/util/cmake/pro2cmake.py @@ -327,6 +327,7 @@ def set_up_cmake_api_calls(): api[2]["qt_add_resource"] = "qt_add_resource" api[2]["qt_add_qml_module"] = "qt_add_qml_module" api[2]["qt_add_cmake_library"] = "qt_add_cmake_library" + api[2]["qt_add_3rdparty_library"] = "qt_add_3rdparty_library" return api @@ -2802,6 +2803,41 @@ def write_main_part( cm_fh.write(ignored_keys_report) +def write_3rdparty_library(cm_fh: IO[str], scope: Scope, *, indent: int = 0) -> str: + + # Remove default QT libs. + scope._append_operation("QT", RemoveOperation(["core", "gui"])) + + target_name = re.sub(r"^qt", "", scope.TARGET) + target_name = target_name.replace("-", "_") + + library_type = "" + + if "dll" in scope.get("CONFIG"): + library_type = "SHARED" + else: + library_type = "STATIC" + + extra_lines = [] + + if library_type: + extra_lines.append(library_type) + + write_main_part( + cm_fh, + target_name, + "Generic Library", + get_cmake_api_call("qt_add_3rdparty_library"), + scope, + extra_lines=extra_lines, + indent=indent, + known_libraries={}, + extra_keys=[], + ) + + return target_name + + def write_generic_library(cm_fh: IO[str], scope: Scope, *, indent: int = 0) -> str: target_name = scope.TARGET @@ -3524,6 +3560,9 @@ def handle_app_or_lib( if is_jar: write_jar(cm_fh, scope, indent=indent) + elif "qt_helper_lib" in scope.get("_LOADED"): + assert not is_example + target = write_3rdparty_library(cm_fh, scope, indent=indent) elif is_example: target = write_example(cm_fh, scope, gui, indent=indent, is_plugin=is_plugin) elif is_qt_plugin: