diff options
-rw-r--r-- | cmake/QtDeclarativeSetup.cmake | 10 | ||||
-rw-r--r-- | src/qml/Qt6QmlMacros.cmake | 95 | ||||
-rw-r--r-- | src/qml/Qt6QmlResolveMetatypesDependencies.cmake | 60 | ||||
-rw-r--r-- | src/qmltyperegistrar/qmltyperegistrar.cpp | 35 |
4 files changed, 150 insertions, 50 deletions
diff --git a/cmake/QtDeclarativeSetup.cmake b/cmake/QtDeclarativeSetup.cmake index 2cd6f56127..116b6013a0 100644 --- a/cmake/QtDeclarativeSetup.cmake +++ b/cmake/QtDeclarativeSetup.cmake @@ -46,3 +46,13 @@ function(qt_declarative_generate_reg_exp_jit_tables consuming_target) target_sources(${consuming_target} PRIVATE ${output_file}) target_include_directories(${consuming_target} PRIVATE $<BUILD_INTERFACE:${generate_dir}>) endfunction() + +# special case to set the qmltype resolve dependencies script at build time +set(QT_QMTYPES_RESOLVE_DEPENDENCIES_SCRIPT + "${CMAKE_CURRENT_SOURCE_DIR}/src/qml/Qt6QmlResolveMetatypesDependencies.cmake" +) + +# install QmlResolveDependency script +qt_copy_or_install(FILES "src/qml/Qt6QmlResolveMetatypesDependencies.cmake" + DESTINATION "${QT_CONFIG_INSTALL_DIR}/${INSTALL_CMAKE_NAMESPACE}Qml" +) diff --git a/src/qml/Qt6QmlMacros.cmake b/src/qml/Qt6QmlMacros.cmake index 8b8ec045d3..dfd556375e 100644 --- a/src/qml/Qt6QmlMacros.cmake +++ b/src/qml/Qt6QmlMacros.cmake @@ -416,42 +416,33 @@ function(qt6_target_qml_files target) file(APPEND ${qmldir_file} ${file_contents}) endfunction() -function(__qt6_extract_dependencies target out_list) - set(dep_list) - get_target_property(link_dependencies ${target} INTERFACE_LINK_LIBRARIES) - foreach(dep IN LISTS link_dependencies) - string(FIND ${dep} "Qt::" qt_loc) - if (NOT ${qt_loc} EQUAL -1) - - if (NOT ${qt_loc} EQUAL 0) - # probably stuck in a generator expression - string(SUBSTRING "${dep}" ${qt_loc} -1 dep_fixed) - string(FIND ${dep_fixed} ">" qt_loc) - if (${qt_loc} EQUAL -1) - message(FATAL_ERROR "Expected generator expression for ${target}' depdency ${dep}") - endif() - string(SUBSTRING ${dep_fixed} 0 ${qt_loc} dep) - endif() - - list(APPEND dep_list ${dep}) - __qt6_extract_dependencies(${dep} recurse_list) - list(APPEND dep_list ${recurse_list}) - endif() - endforeach() - set(${out_list} ${dep_list} PARENT_SCOPE) -endfunction() - function(qt6_qml_type_registration target) + get_target_property(import_name ${target} QT_QML_MODULE_URI) if (NOT import_name) message(FATAL_ERROR "Target ${target} is not a QML module") endif() - qt6_generate_meta_types_json_file(${target}) + cmake_parse_arguments(args "COPY_OVER_INSTALL" "INSTALL_DIR" "" ${ARGN}) + + set(meta_types_args) + if (arg_INSTALL_DIR) + list(APPEND meta_types_args INSTALL_DIR "${arg_INSTALL_DIR}") + endif() + if (arg_COPY_OVER_INSTALL) + list(APPEND meta_types_args COPY_OVER_INSTALL) + endif() + + qt6_generate_meta_types_json_file(${target} ${meta_types_args}) get_target_property(import_version ${target} QT_QML_MODULE_VERSION) get_target_property(target_source_dir ${target} SOURCE_DIR) get_target_property(target_binary_dir ${target} BINARY_DIR) + get_target_property(target_metatypes_dep_file ${target} INTERFACE_QT_META_TYPES_BUILD_DEP_FILE) + get_target_property(target_metatypes_file ${target} INTERFACE_QT_META_TYPES_BUILD_FILE) + if (NOT target_metatypes_dep_file) + message(FATAL_ERROR "Target ${target} does not have a meta types dependency file") + endif() # Extract major and minor version if (NOT import_version MATCHES "[0-9]+\\.[0-9]+") @@ -474,28 +465,34 @@ function(qt6_qml_type_registration target) --minor-version=${minor_version} ) - # Extra metatypes.json - set(foreign_types) - set(link_dependencies) - __qt6_extract_dependencies(${target} link_dependencies) - list(REMOVE_DUPLICATES link_dependencies) - foreach(dep IN LISTS link_dependencies) - string(SUBSTRING ${dep} 4 -1 module_name) - string(TOLOWER "qt6${module_name}_${CMAKE_BUILD_TYPE}_metatypes.json" metatypes_file) - - set(module_metatypes_file "${CMAKE_BINARY_DIR}/lib/metatypes/${metatypes_file}") - set(installed_metatypes_file "${Qt6_DIR}/../../metatypes/${metatypes_file}") - if (EXISTS ${module_metatypes_file}) - list(APPEND foreign_types ${module_metatypes_file}) - elseif (EXISTS ${installed_metatypes_file}) - list(APPEND foreign_types ${installed_metatypes_file}) - endif() - endforeach() + # Run a script to recursively evaluate all the metatypes.json files in order + # to collect all foreign types. + set(foreign_types_file "${target_binary_dir}/qmltypes/foreign_types.txt") + set(foreign_types_file_tmp "${target_binary_dir}/qmltypes/foreign_types.txt.tmp") + + if (NOT QT_QMTYPES_RESOLVE_DEPENDENCIES_SCRIPT) + set("${Qt6Qml_DIR}/Qt6QmlResolveMetatypesDependencies.cmake") + endif() + + add_custom_target(${target}_resolve_foreign_types + DEPENDS ${target_metatypes_file} + COMMAND ${CMAKE_COMMAND} + -DOUTPUT_FILE:PATH="${foreign_types_file_tmp}" + -DMAIN_DEP_FILE:PATH="${target_metatypes_dep_file}" + -DQT_INSTALL_DIR:PATH="${Qt6_DIR}/../../.." + -P "${QT_QMTYPES_RESOLVE_DEPENDENCIES_SCRIPT}" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${foreign_types_file_tmp}" + "${foreign_types_file}" + BYPRODUCTS ${foreign_types_file} + COMMAND_EXPAND_LISTS + COMMENT "Resolving foreign type dependencies for target ${target}" + ) + + add_dependencies(${target}_resolve_foreign_types ${target}_autogen) - list(REMOVE_DUPLICATES foreign_types) - string(REPLACE ";" "," foreign_types_list "${foreign_types}") list(APPEND cmd_args - "--foreign-types=${foreign_types_list}" + "@${foreign_types_file}" ) set(dependencies_json_file "${target_source_dir}/dependencies.json") @@ -507,7 +504,7 @@ function(qt6_qml_type_registration target) list(APPEND cmd_args --private-includes) endif() - get_target_property(target_metatypes_json_file ${target} QT_MODULE_META_TYPES_FILE) + get_target_property(target_metatypes_json_file ${target} INTERFACE_QT_META_TYPES_BUILD_FILE) if (NOT target_metatypes_json_file) message(FATAL_ERROR "Need target metatypes.json file") endif() @@ -516,15 +513,15 @@ function(qt6_qml_type_registration target) set(type_registration_cpp_file "${target_binary_dir}/${type_registration_cpp_file}") add_custom_command(OUTPUT ${type_registration_cpp_file} - DEPENDS ${foreign_types} ${target_metatypes_json_file} + DEPENDS ${foreign_types_file} ${target_metatypes_json_file} COMMAND ${CMAKE_COMMAND} -E env PATH=${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR} $<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::qmltyperegistrar> ${cmd_args} -o ${type_registration_cpp_file} ${target_metatypes_json_file} - COMMENT "Automatic QML type registration for target ${target}" COMMAND_EXPAND_LISTS + COMMENT "Automatic QML type registration for target ${target}" ) target_sources(${target} PRIVATE ${type_registration_cpp_file}) diff --git a/src/qml/Qt6QmlResolveMetatypesDependencies.cmake b/src/qml/Qt6QmlResolveMetatypesDependencies.cmake new file mode 100644 index 0000000000..0626b18a62 --- /dev/null +++ b/src/qml/Qt6QmlResolveMetatypesDependencies.cmake @@ -0,0 +1,60 @@ +# +# Resolve dependencies +# + +if (NOT MAIN_DEP_FILE) + message(FATAL_ERROR "MAIN_DEP_FILE file not specified") +endif() + +if (NOT QT_INSTALL_DIR) + message(FATAL_ERROR "QT_INSTALL_DIR was not specified") +endif() + +if (NOT OUTPUT_FILE) + message(FATAL_ERROR "OUTPUT_FILE not specified") +endif() + +# Read main dep file +if (NOT EXISTS "${MAIN_DEP_FILE}") + message(FATAL_ERROR "${MAIN_DEP_FILE} does not exist") +endif() + +file(STRINGS "${MAIN_DEP_FILE}" remaining) +set(metatypes_list) +while(remaining) + + # Pop element off the list + list(POP_FRONT remaining current) + + string(REPLACE "=" ";" file_list "${current}") + list(GET file_list 0 metatypes_file) + list(GET file_list 1 metatypes_dep_file) + + if (NOT IS_ABSOLUTE "${metatypes_file}") + set(metatypes_file "${QT_INSTALL_DIR}/${metatypes_file}") + set(metatypes_dep_file "${QT_INSTALL_DIR}/${metatypes_dep_file}") + endif() + + if (NOT EXISTS "${metatypes_file}") + message(FATAL_ERROR "${metatypes_file} does not exist") + endif() + if (NOT EXISTS "${metatypes_dep_file}") + message(FATAL_ERROR "${metatypes_dep_file} does not exist") + endif() + + list(APPEND metatypes_list "${metatypes_file}") + + file(STRINGS ${metatypes_dep_file} dep_string) + if (dep_string) + list(APPEND remaining "${dep_string}") + endif() +endwhile() + +list(REMOVE_DUPLICATES metatypes_list) +list(JOIN metatypes_list "," metatypes) + +if (metatypes) + file(WRITE ${OUTPUT_FILE} "--foreign-types=${metatypes}\n") +else() + file(WRITE ${OUTPUT_FILE} "\n") +endif() diff --git a/src/qmltyperegistrar/qmltyperegistrar.cpp b/src/qmltyperegistrar/qmltyperegistrar.cpp index 49c9fccb66..4738e28314 100644 --- a/src/qmltyperegistrar/qmltyperegistrar.cpp +++ b/src/qmltyperegistrar/qmltyperegistrar.cpp @@ -57,6 +57,35 @@ static bool acceptClassForQmlTypeRegistration(const QJsonObject &classDef) return false; } +static bool argumentsFromCommandLineAndFile(QStringList &allArguments, const QStringList &arguments) +{ + allArguments.reserve(arguments.size()); + for (const QString &argument : arguments) { + // "@file" doesn't start with a '-' so we can't use QCommandLineParser for it + if (argument.startsWith(QLatin1Char('@'))) { + QString optionsFile = argument; + optionsFile.remove(0, 1); + if (optionsFile.isEmpty()) { + fprintf(stderr, "The @ option requires an input file"); + return false; + } + QFile f(optionsFile); + if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) { + fprintf(stderr, "Cannot open options file specified with @"); + return false; + } + while (!f.atEnd()) { + QString line = QString::fromLocal8Bit(f.readLine().trimmed()); + if (!line.isEmpty()) + allArguments << line; + } + } else { + allArguments << argument; + } + } + return true; +} + static QVector<QJsonObject> foreignRelatedTypes(const QVector<QJsonObject> &types, const QVector<QJsonObject> &foreignTypes) { @@ -229,7 +258,11 @@ int main(int argc, char **argv) parser.addPositionalArgument(QStringLiteral("[MOC generated json file]"), QStringLiteral("MOC generated json output.")); - parser.process(app); + QStringList arguments; + if (!argumentsFromCommandLineAndFile(arguments, app.arguments())) + return EXIT_FAILURE; + + parser.process(arguments); FILE *output = stdout; QScopedPointer<FILE, ScopedPointerFileCloser> outputFile; |