aboutsummaryrefslogtreecommitdiffstats
path: root/tools/qmlimportscanner
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@qt.io>2020-08-10 11:50:39 +0200
committerAlexandru Croitor <alexandru.croitor@qt.io>2020-08-13 14:02:32 +0200
commit7e94cf8296859ea72a7caaf1a454fe6767fce450 (patch)
tree657569f12a48a3a1c414b9dda2f307a8b2821fcd /tools/qmlimportscanner
parent9a79791e7975de811102f89686a5d631eeac9d16 (diff)
CMake: Initial work on handling Qt Qml static plugins
In Qt 5 we added a QmlImportScanner package that provided a qt5_import_qml_plugins() function. Calling it with a target ensured running qmlimportscanner to find and link necessary qml static plugins for an application to work. This is the initial port of that to Qt 6, with a few differences. It introduces 2 function names, the version-less one and qt6_ prefixed one, qt_import_qml_plugins and qt6_import_qml_plugins. Implementation notes. In Qt 5 we figured out what link flags to pass by parsing the plugin prl files. In Qt 6, CMake can generate appropriate plugin targets with dependencies, as well as Config files that can look for the dependent packages. Use that information for finding the dependencies and linking. Note this relies on the assumption that find_package(Qt6Qml) will already include all available Qml plugin Config files, so that the targets exist in scope by the time qt_import_qml_plugins is called and links against those targets. The automatic inclusion is handled by a change in qtbase. In Qt 5 the function was available as part of QmlImportScanner package. In Qt 6 the function is moved to QmlMacros, so it's enough to find_package(Qt6Qml) to use it. A dummy QmlImportScanner package is provided for backwards compatibility, that simply finds the Qml package. Another change is to make the resource name added by qt6_target_qml_files unique (include the target name), because qmlcachegen generates a cpp file with a static initializer function name that includes the resource name. This caused duplicate symbol errors when linking more than one qtquickcontrols2 style plugin into an application when the resource name was not unique. There are a couple of TODOs left: - Figure out if it's possible to automatically call qt_import_qml_plugins for applications that link against Qml. Perhaps using our hacky scope finalizers. - Figure out how to handle scanning of resources. Task-number: QTBUG-85961 Task-number: QTBUG-85994 Change-Id: I42f61e4acc6f74a3cdc030dba9e41ce789bc28f6 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
Diffstat (limited to 'tools/qmlimportscanner')
-rw-r--r--tools/qmlimportscanner/CMakeLists.txt45
-rw-r--r--tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in194
-rw-r--r--tools/qmlimportscanner/Qt5QmlImportScannerTemplate.cpp.in5
-rw-r--r--tools/qmlimportscanner/Qt6QmlImportScannerConfig.cmake.in5
-rw-r--r--tools/qmlimportscanner/qmlimportscanner.pro19
5 files changed, 60 insertions, 208 deletions
diff --git a/tools/qmlimportscanner/CMakeLists.txt b/tools/qmlimportscanner/CMakeLists.txt
index dfe24cfc26..eaf5a9f3cb 100644
--- a/tools/qmlimportscanner/CMakeLists.txt
+++ b/tools/qmlimportscanner/CMakeLists.txt
@@ -20,6 +20,51 @@ qt_add_tool(${target_name}
Qt::QmlDevToolsPrivate
)
+# special case begin
+# Create a dummy package that will just find Qml package, for backwards compatibility reasons.
+set(target "QmlImportScanner")
+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})
+
+# Configure and install Config and version file.
+configure_package_config_file(
+ "${CMAKE_CURRENT_LIST_DIR}/Qt6QmlImportScannerConfig.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(FILES
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
+ DESTINATION "${config_install_dir}"
+ COMPONENT Devel
+)
+
+# Configure and install ModuleDependencies file.
+set(third_party_deps "")
+set(main_module_tool_deps "")
+set(target_deps "${INSTALL_CMAKE_NAMESPACE}Qml\;${PROJECT_VERSION}")
+set(qt_module_dependencies "Qml")
+configure_file(
+ "${QT_CMAKE_DIR}/QtModuleDependencies.cmake.in"
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake"
+ @ONLY
+)
+
+qt_install(FILES
+ "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake"
+ DESTINATION "${config_install_dir}"
+ COMPONENT Devel
+)
+
+# special case end
+
#### Keys ignored in scope 1:.:.:qmlimportscanner.pro:<TRUE>:
# CMAKE_BIN_DIR = "$$cmakeRelativePath($$[QT_HOST_BINS], $$[QT_INSTALL_PREFIX])"
# CMAKE_DEBUG_TYPE = <EMPTY>
diff --git a/tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in b/tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in
deleted file mode 100644
index f92b8d295d..0000000000
--- a/tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in
+++ /dev/null
@@ -1,194 +0,0 @@
-include(CMakeParseArguments)
-
-function(QT5_IMPORT_QML_PLUGINS target)
-!!IF !isEmpty(CMAKE_STATIC_TYPE)
- set(options)
- set(oneValueArgs \"PATH_TO_SCAN\")
- set(multiValueArgs)
-
- cmake_parse_arguments(arg \"${options}\" \"${oneValueArgs}\" \"${multiValueArgs}\" ${ARGN})
- if(NOT arg_PATH_TO_SCAN)
- set(arg_PATH_TO_SCAN \"${CMAKE_CURRENT_SOURCE_DIR}\")
- endif()
-
- # Find location of qmlimportscanner.
- find_package(Qt5 COMPONENTS Core)
-!!IF isEmpty(CMAKE_BIN_DIR_IS_ABSOLUTE)
- set(tool_path
- \"${_qt5Core_install_prefix}/$${CMAKE_BIN_DIR}qmlimportscanner$$CMAKE_BIN_SUFFIX\")
-!!ELSE
- set(tool_path \"$${CMAKE_BIN_DIR}qmlimportscanner$$CMAKE_BIN_SUFFIX\")
-!!ENDIF
- if(NOT EXISTS \"${tool_path}\" )
- message(FATAL_ERROR \"The package \\\"Qt5QmlImportScannerConfig\\\" references the file
- \\\"${tool_path}\\\"
-but this file does not exist. Possible reasons include:
-* The file was deleted, renamed, or moved to another location.
-* An install or uninstall procedure did not complete successfully.
-* The installation package was faulty.
-\")
- endif()
-
- # Find location of qml dir.
-!!IF isEmpty(CMAKE_QML_DIR_IS_ABSOLUTE)
- set(qml_path \"${_qt5Core_install_prefix}/$${CMAKE_QML_DIR}\")
-!!ELSE
- set(qml_path \"$${CMAKE_QML_DIR}\")
-!!ENDIF
-
- # Small macro to avoid duplicating code in two different loops.
- macro(_qt5_QmlImportScanner_parse_entry)
- set(entry_name \"qml_import_scanner_import_${idx}\")
- cmake_parse_arguments(\"entry\"
- \"\"
- \"CLASSNAME;NAME;PATH;PLUGIN;RELATIVEPATH;TYPE;VERSION;\" \"\"
- ${${entry_name}})
- endmacro()
-
- # Macro used to populate the dependency link flags for a certain configuriation (debug vs
- # release) of a plugin.
- macro(_qt5_link_to_QmlImportScanner_library_dependencies Plugin Configuration PluginLocation
- IsDebugAndRelease)
-
- set_property(TARGET \"${Plugin}\" APPEND PROPERTY IMPORTED_CONFIGURATIONS ${Configuration})
- set(_imported_location \"${PluginLocation}\")
- _qt5_Core_check_file_exists(\"${_imported_location}\")
- set_target_properties(\"${Plugin}\" PROPERTIES
- \"IMPORTED_LOCATION_${Configuration}\" \"${_imported_location}\"
- )
-
- set(_static_deps
- ${_Qt5${entry_PLUGIN}_STATIC_${Configuration}_LIB_DEPENDENCIES}
- )
-
- if(NOT "${IsDebugAndRelease}")
- set(_genex_condition \"1\")
- else()
- if("${Configuration}" STREQUAL "DEBUG")
- set(_genex_condition \"$<CONFIG:Debug>\")
- else()
- set(_genex_condition \"$<NOT:$<CONFIG:Debug>>\")
- endif()
- endif()
- if(_static_deps)
- set(_static_deps_genex \"$<${_genex_condition}:${_static_deps}>\")
- target_link_libraries(${imported_target} INTERFACE \"${_static_deps_genex}\")
- endif()
-
- set(_static_link_flags \"${_Qt5${entry_PLUGIN}_STATIC_${Configuration}_LINK_FLAGS}\")
- if(NOT CMAKE_VERSION VERSION_LESS \"3.13\" AND _static_link_flags)
- set(_static_link_flags_genex \"$<${_genex_condition}:${_static_link_flags}>\")
- target_link_options(${imported_target} INTERFACE \"${_static_link_flags_genex}\")
- endif()
- endmacro()
-
- # Run qmlimportscanner and include the generated cmake file.
- set(qml_imports_file_path
- \"${CMAKE_CURRENT_BINARY_DIR}/Qt5_QmlPlugins_Imports_${target}.cmake\")
-
- message(STATUS \"Running qmlimportscanner to find used QML plugins. \")
- execute_process(COMMAND
- \"${tool_path}\" \"${arg_PATH_TO_SCAN}\" -importPath \"${qml_path}\"
- -cmake-output
- OUTPUT_FILE \"${qml_imports_file_path}\")
-
- include(\"${qml_imports_file_path}\" OPTIONAL RESULT_VARIABLE qml_imports_file_path_found)
- if(NOT qml_imports_file_path_found)
- message(FATAL_ERROR \"Could not find ${qml_imports_file_path} which was supposed to be generated by qmlimportscanner.\")
- endif()
-
- # Parse the generate cmake file.
- # It is possible for the scanner to find no usage of QML, in which case the import count is 0.
- if(qml_import_scanner_imports_count)
- set(added_plugins \"\")
- foreach(idx RANGE \"${qml_import_scanner_imports_count}\")
- _qt5_QmlImportScanner_parse_entry()
- if(entry_PATH AND entry_PLUGIN)
- # Sometimes a plugin appears multiple times with different versions.
- # Make sure to process it only once.
- list(FIND added_plugins \"${entry_PLUGIN}\" _index)
- if(NOT _index EQUAL -1)
- continue()
- endif()
- list(APPEND added_plugins \"${entry_PLUGIN}\")
-
- # Add an imported target that will contain the link libraries and link options read
- # from one plugin prl file. This target will point to the actual plugin and contain
- # static dependency libraries and link flags.
- # By creating a target for each qml plugin, CMake will take care of link flag
- # deduplication.
- set(imported_target \"${target}_QmlImport_${entry_PLUGIN}\")
- add_library(\"${imported_target}\" MODULE IMPORTED)
- target_link_libraries(\"${target}\" PRIVATE \"${imported_target}\")
-
- # Read static library dependencies from the plugin .prl file.
- # And then set the link flags to the library dependencies extracted from the .prl
- # file.
-!!IF !isEmpty(CMAKE_RELEASE_TYPE)
- _qt5_Core_process_prl_file(
- \"${entry_PATH}/$$QMAKE_PREFIX_STATICLIB${entry_PLUGIN}$${CMAKE_QML_PLUGIN_SUFFIX_RELEASE}.prl\" RELEASE
- _Qt5${entry_PLUGIN}_STATIC_RELEASE_LIB_DEPENDENCIES
- _Qt5${entry_PLUGIN}_STATIC_RELEASE_LINK_FLAGS
- )
- _qt5_link_to_QmlImportScanner_library_dependencies(
- \"${imported_target}\"
- RELEASE
- \"${entry_PATH}/$$QMAKE_PREFIX_STATICLIB${entry_PLUGIN}$${CMAKE_QML_PLUGIN_SUFFIX_RELEASE}.$$QMAKE_EXTENSION_STATICLIB\"
- $${CMAKE_DEBUG_AND_RELEASE})
-!!ENDIF
-
-!!IF !isEmpty(CMAKE_DEBUG_TYPE)
- _qt5_Core_process_prl_file(
- \"${entry_PATH}/$$QMAKE_PREFIX_STATICLIB${entry_PLUGIN}$${CMAKE_QML_PLUGIN_SUFFIX_DEBUG}.prl\" DEBUG
- _Qt5${entry_PLUGIN}_STATIC_DEBUG_LIB_DEPENDENCIES
- _Qt5${entry_PLUGIN}_STATIC_DEBUG_LINK_FLAGS
- )
- _qt5_link_to_QmlImportScanner_library_dependencies(
- \"${imported_target}\"
- DEBUG
- \"${entry_PATH}/$$QMAKE_PREFIX_STATICLIB${entry_PLUGIN}$${CMAKE_QML_PLUGIN_SUFFIX_DEBUG}.$$QMAKE_EXTENSION_STATICLIB\"
- $${CMAKE_DEBUG_AND_RELEASE})
-!!ENDIF
- endif()
- endforeach()
-
- # Generate content for plugin initialization cpp file.
- set(added_imports \"\")
- set(qt5_qml_import_cpp_file_content \"\")
- foreach(idx RANGE \"${qml_import_scanner_imports_count}\")
- _qt5_QmlImportScanner_parse_entry()
- if(entry_PLUGIN)
- if(entry_CLASSNAME)
- list(FIND added_imports \"${entry_PLUGIN}\" _index)
- if(_index EQUAL -1)
- string(APPEND qt5_qml_import_cpp_file_content
- \"Q_IMPORT_PLUGIN(${entry_CLASSNAME})\n\")
- list(APPEND added_imports \"${entry_PLUGIN}\")
- endif()
- else()
- message(FATAL_ERROR
- \"Plugin ${entry_PLUGIN} is missing a classname entry, please add one to the qmldir file.\")
- endif()
- endif()
- endforeach()
-
- # Write to the generated file, and include it as a source for the given target.
- set(generated_import_cpp_path
- \"${CMAKE_CURRENT_BINARY_DIR}/Qt5_QmlPlugins_Imports_${target}.cpp\")
- configure_file(\"${Qt5QmlImportScanner_DIR}/Qt5QmlImportScannerTemplate.cpp.in\"
- \"${generated_import_cpp_path}\"
- @ONLY)
- target_sources(${target} PRIVATE \"${generated_import_cpp_path}\")
- endif()
-!!ENDIF // !isEmpty(CMAKE_STATIC_TYPE)
-endfunction()
-
-if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
- function(qt_import_qml_plugins)
- if(QT_DEFAULT_MAJOR_VERSION EQUAL 5)
- qt5_import_qml_plugins(${ARGV})
- elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
- qt6_import_qml_plugins(${ARGV})
- endif()
- endfunction()
-endif()
diff --git a/tools/qmlimportscanner/Qt5QmlImportScannerTemplate.cpp.in b/tools/qmlimportscanner/Qt5QmlImportScannerTemplate.cpp.in
deleted file mode 100644
index 4ed747a555..0000000000
--- a/tools/qmlimportscanner/Qt5QmlImportScannerTemplate.cpp.in
+++ /dev/null
@@ -1,5 +0,0 @@
-// This file is autogenerated by CMake. It imports static plugin classes for
-// static plugins used by QML imports.
-#include <QtPlugin>
-
-@qt5_qml_import_cpp_file_content@
diff --git a/tools/qmlimportscanner/Qt6QmlImportScannerConfig.cmake.in b/tools/qmlimportscanner/Qt6QmlImportScannerConfig.cmake.in
new file mode 100644
index 0000000000..0383b547ad
--- /dev/null
+++ b/tools/qmlimportscanner/Qt6QmlImportScannerConfig.cmake.in
@@ -0,0 +1,5 @@
+# The functionality that was provided in the Qt5 package was moved to the Qml package.
+# Defers to that package and it macros.
+include(CMakeFindDependencyMacro)
+include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Dependencies.cmake")
+set("@INSTALL_CMAKE_NAMESPACE@@target@_FOUND" TRUE)
diff --git a/tools/qmlimportscanner/qmlimportscanner.pro b/tools/qmlimportscanner/qmlimportscanner.pro
index 9fd2a38956..0d2dc22ea2 100644
--- a/tools/qmlimportscanner/qmlimportscanner.pro
+++ b/tools/qmlimportscanner/qmlimportscanner.pro
@@ -47,15 +47,16 @@ qtConfig(debug_and_release) {
CMAKE_DEBUG_AND_RELEASE = FALSE
}
-equals(QMAKE_HOST.os, Windows): CMAKE_BIN_SUFFIX = ".exe"
-cmake_config_file.input = $$PWD/Qt5QmlImportScannerConfig.cmake.in
-cmake_config_file.output = $$MODULE_BASE_OUTDIR/lib/cmake/Qt5QmlImportScanner/Qt5QmlImportScannerConfig.cmake
-QMAKE_SUBSTITUTES += cmake_config_file
-
-cmake_build_integration.files = $$cmake_config_file.output $$PWD/Qt5QmlImportScannerTemplate.cpp.in
-cmake_build_integration.path = $$[QT_INSTALL_LIBS]/cmake/Qt5QmlImportScanner
-prefix_build: INSTALLS += cmake_build_integration
-else: COPIES += cmake_build_integration
+# The qml import scanner CMake files are now only created by the Qt 6 CMake build.
+#equals(QMAKE_HOST.os, Windows): CMAKE_BIN_SUFFIX = ".exe"
+#cmake_config_file.input = $$PWD/Qt5QmlImportScannerConfig.cmake.in
+#cmake_config_file.output = $$MODULE_BASE_OUTDIR/lib/cmake/Qt5QmlImportScanner/Qt5QmlImportScannerConfig.cmake
+#QMAKE_SUBSTITUTES += cmake_config_file
+
+#cmake_build_integration.files = $$cmake_config_file.output $$PWD/Qt5QmlImportScannerTemplate.cpp.in
+#cmake_build_integration.path = $$[QT_INSTALL_LIBS]/cmake/Qt5QmlImportScanner
+#prefix_build: INSTALLS += cmake_build_integration
+#else: COPIES += cmake_build_integration
QMAKE_TARGET_DESCRIPTION = QML Import Scanner