aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/Qt6QmlMacros.cmake
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 /src/qml/Qt6QmlMacros.cmake
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 'src/qml/Qt6QmlMacros.cmake')
-rw-r--r--src/qml/Qt6QmlMacros.cmake132
1 files changed, 131 insertions, 1 deletions
diff --git a/src/qml/Qt6QmlMacros.cmake b/src/qml/Qt6QmlMacros.cmake
index 24a5eb533b..bf59fba446 100644
--- a/src/qml/Qt6QmlMacros.cmake
+++ b/src/qml/Qt6QmlMacros.cmake
@@ -429,7 +429,8 @@ function(qt6_target_qml_files target)
math(EXPR new_count "${resource_count} + 1")
set_target_properties(${target} PROPERTIES QT6_QML_MODULE_ADD_QML_FILES_COUNT ${new_count})
- qt6_add_resources(${target} "qml_files${new_count}"
+ # TODO: Fix this if it blows up on Windows due to too long target name.
+ qt6_add_resources(${target} "${target}_qml_files_resource_${new_count}"
FILES ${arg_FILES}
OUTPUT_TARGETS resource_targets
)
@@ -833,3 +834,132 @@ function(qt6_quick_compiler_process_resources target resource_name)
set(${arg_OUTPUT_REMAINING_RESOURCES} ${resource_files} PARENT_SCOPE)
set(${arg_OUTPUT_RESOURCE_NAME} ${resource_name} PARENT_SCOPE)
endfunction()
+
+include(CMakeParseArguments)
+
+function(qt6_import_qml_plugins target)
+ if(${QT_CMAKE_EXPORT_NAMESPACE}_IS_SHARED_LIBS_BUILD)
+ return()
+ endif()
+ 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.
+ get_target_property(tool_path ${QT_CMAKE_EXPORT_NAMESPACE}::qmlimportscanner IMPORTED_LOCATION)
+ if(NOT tool_path)
+ set(configs "RELWITHDEBINFO;RELEASE;MINSIZEREL;DEBUG")
+ foreach(config ${configs})
+ get_target_property(tool_path Qt6::qmlimportscanner IMPORTED_LOCATION_${config})
+ if(tool_path)
+ break()
+ endif()
+ endforeach()
+ endif()
+
+ if(NOT EXISTS "${tool_path}")
+ message(FATAL_ERROR "The package \"QmlImportScanner\" 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.
+ # TODO: qt.prf implies that there might be more than one qml import path to pass to
+ # qmlimportscanner.
+ set(qml_path "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_QML}")
+
+ # Small macro to avoid duplicating code in two different loops.
+ macro(_qt6_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()
+
+ # Run qmlimportscanner and include the generated cmake file.
+ set(qml_imports_file_path
+ "${CMAKE_CURRENT_BINARY_DIR}/Qt6_QmlPlugins_Imports_${target}.cmake")
+
+ # TODO: QTBUG-85994 Figure out how to handle resources like in fix for QTBUG-82873.
+ 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 generated 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}")
+ _qt6_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}")
+
+ # Link against the Qml plugin. The assumption is that all Qml plugins are already
+ # find_package()'d by the Qml package, so we can safely link against the target.
+ target_link_libraries("${target}" PRIVATE
+ "${QT_CMAKE_EXPORT_NAMESPACE}::${entry_PLUGIN}")
+ endif()
+ endforeach()
+
+ # Generate content for plugin initialization cpp file.
+ set(added_imports "")
+ set(qt_qml_import_cpp_file_content "")
+ foreach(idx RANGE "${qml_import_scanner_imports_count}")
+ _qt6_QmlImportScanner_parse_entry()
+ if(entry_PLUGIN)
+ if(entry_CLASSNAME)
+ list(FIND added_imports "${entry_PLUGIN}" _index)
+ if(_index EQUAL -1)
+ string(APPEND qt_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}/Qt6_QmlPlugins_Imports_${target}.cpp")
+ configure_file("${Qt6Qml_DIR}/Qt6QmlImportScannerTemplate.cpp.in"
+ "${generated_import_cpp_path}"
+ @ONLY)
+ target_sources(${target} PRIVATE "${generated_import_cpp_path}")
+ endif()
+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()