summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmake/QtBuild.cmake229
-rw-r--r--cmake/QtProperties.cmake35
-rwxr-xr-xutil/cmake/pro2cmake.py67
3 files changed, 238 insertions, 93 deletions
diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake
index 35334353bf..f0a8c34875 100644
--- a/cmake/QtBuild.cmake
+++ b/cmake/QtBuild.cmake
@@ -1853,6 +1853,7 @@ endfunction()
#
# TARGET_PATH: QML target path
# QML_FILES: List of QML Files
+# RESOURCE_PREFIX: Resource prefix to be prepended to the module's TARGET_PATH
#
function(add_quick_compiler_target target)
@@ -1863,9 +1864,17 @@ Please add QmlTools to your find_package command."
endif()
qt_parse_all_arguments(arg "add_quick_compiler_target"
- "" "TARGET_PATH" "QML_FILES" ${ARGN}
+ "" "TARGET_PATH;RESOURCE_PREFIX" "QML_FILES" ${ARGN}
)
+ if (NOT arg_RESOURCE_PREFIX)
+ message(FATAL_ERROR "add_quick_compiler_target: no resource prefix specified, please specify one using the RESOURCE_PREFIX")
+ endif()
+
+ if (NOT arg_TARGET_PATH)
+ message(FATAL_ERROR "add_quick_compiler_target: no target path specified, please specify one using the TARGET_PATH")
+ endif()
+
if (arg_QML_FILES)
# enable quick compiler and qml loader
@@ -1873,7 +1882,7 @@ Please add QmlTools to your find_package command."
get_filename_component(file_absolute ${file} ABSOLUTE)
file(RELATIVE_PATH file_relative ${CMAKE_CURRENT_SOURCE_DIR} ${file_absolute})
qt_get_relative_resource_path_for_file(alias ${file})
- set(file_resource_path "/qt-project.org/import/${arg_TARGET_PATH}/${alias}")
+ set(file_resource_path "${arg_RESOURCE_PREFIX}/${arg_TARGET_PATH}/${alias}")
list(APPEND file_resource_paths ${file_resource_path})
string(REGEX REPLACE "\.js$" "_js" compiled_file ${file_relative})
string(REGEX REPLACE "\.mjs$" "_mjs" compiled_file ${compiled_file})
@@ -1891,13 +1900,17 @@ Please add QmlTools to your find_package command."
target_sources(${target} PRIVATE ${compiled_file})
endforeach()
- set(qmlcache_loader_list "${CMAKE_CURRENT_BINARY_DIR}/qmlcache/${target}_qml_loader_file_list.rsp")
+ # Use hash of the current list of qml files so the generated loader
+ # cpp file and list should be unique between invocation of this
+ # function
+ string(MD5 unique_id "${arg_QML_FILES}")
+ set(qmlcache_loader_list "${CMAKE_CURRENT_BINARY_DIR}/qmlcache/${unique_id}_${target}_qml_loader_file_list.rsp")
file(GENERATE
OUTPUT ${qmlcache_loader_list}
CONTENT "$<JOIN:${file_resource_paths},\n>"
)
- set(qmlcache_loader_file "${CMAKE_CURRENT_BINARY_DIR}/qmlcache/qmlcache_loader.cpp")
+ set(qmlcache_loader_file "${CMAKE_CURRENT_BINARY_DIR}/qmlcache/${unique_id}_qmlcache_loader.cpp")
string(REPLACE "/" "_" resource_name ${arg_TARGET_PATH})
string(REPLACE "." "_" resource_name ${resource_name})
set(resource_name "qmake_${resource_name}.qrc")
@@ -1914,56 +1927,142 @@ Please add QmlTools to your find_package command."
endif()
endfunction()
+# Note this function is a temporary implementation that will be removed
+# in the next patch. It just aggregates all special processing that used
+# to be done on qml files.
+function(target_qml_files target)
+ set(qml_files ${ARGV})
+ list(REMOVE_ITEM qml_files ${target})
+
+ if (NOT qml_files)
+ message(FATAL_ERROR "Calling target_qml_files without any qml files.")
+ endif()
+
+ get_target_property(target_path ${target} QT_QML_MODULE_TARGET_PATH)
+ if (NOT target_path)
+ message(FATAL_ERROR "Calling target_qml_files on a target has not been created via add_qml_module.")
+ endif()
+
+ foreach (qml_file IN LISTS qml_files)
+ if (NOT ${qml_file} MATCHES "\.js$"
+ AND NOT ${qml_file} MATCHES "\.mjs$"
+ AND NOT ${qml_file} MATCHES "\.qml$")
+ message(FATAL_ERROR "target_qml_files, '${qml_file}' is not a valid qml file. Valid extensions are: .js, .mjs and .qml.")
+ endif()
+ endforeach()
+
+
+ get_target_property(install_qml_files ${target} QT_QML_MODULE_INSTALL_QML_FILES)
+ get_target_property(embed_qml_files ${target} QT_QML_MODULE_EMBED_QML_FILES)
+
+ # Only generate compiled caches if we are not embedding
+ if (NOT embed_qml_files AND install_qml_files)
+ add_qmlcachegen_target(${target}
+ QML_FILES ${qml_files}
+ TARGET_PATH ${target_path}
+ )
+ endif()
+
+ if(NOT QT_BUILD_SHARED_LIBS OR embed_qml_files)
+ get_target_property(prefix ${target} QT_QML_MODULE_RESOURCE_PREFIX)
+ string(REPLACE "/" "." uri ${target_path})
+ string(REPLACE "." "_" uri_target ${uri})
+
+ add_quick_compiler_target(${target}
+ TARGET_PATH ${target_path}
+ QML_FILES ${qml_files}
+ RESOURCE_PREFIX ${prefix}
+ )
+ endif()
+
+ if (QT_BUILD_SHARED_LIBS AND arg_QML_FILES AND arg_INSTALL_QML_FILES)
+ qt_copy_or_install(FILES ${arg_QML_FILES}
+ DESTINATION "${qml_module_install_dir}"
+ )
+ endif()
+
+endfunction()
+
+
+function(qt_install_qml_files target)
+
+ qt_parse_all_arguments(arg "qt_install_qml_files"
+ "" "" "FILES" ${ARGN}
+ )
+
+ if (NOT arg_FILES)
+ message(FATAL_ERROR "No files specified for qt_install_qml_files. Please specify them using the FILES parameter.")
+ endif()
+
+ get_target_property(target_path ${target} QT_QML_MODULE_TARGET_PATH)
+ if (NOT target_path)
+ message(FATAL_ERROR "Target ${target} is not a qml module.")
+ endif()
+
+
+ qt_path_join(qml_module_install_dir ${QT_INSTALL_DIR} "${INSTALL_QMLDIR}/${target_path}")
+ qt_copy_or_install(FILES ${arg_FILES}
+ DESTINATION ${qml_module_install_dir}
+ )
+
+endfunction()
+
# This function creates a CMake target for qml modules. It will also make
# sure that if no C++ source are present, that qml files show up in the project
# in an IDE. Finally, it will also create a custom ${target}_qmltypes which
# can be used to generate the respective plugin.qmltypes file.
#
-# EMBED_QML_FILES: All qml files (.js, .mjs and .qml) will be embedded
-# into the binary.
-# INSTALL_QML_FILES: All qml files (.js, .mjs and .qml) will be installed with
-# the module.
+# CPP_PLUGIN: Whether this qml module has any c++ source files.
+# URI: Module's uri.
# TARGET_PATH: Expected installation path for the Qml Module. Equivalent
-# to the module's URI where '.' is replaced with '/'.
-# IMPORT_VERSION: Import version for the qml module
-# IMPORT_NAME: Override for the default import name used in the ${target}_qmltypes
+# to the module's URI where '.' is replaced with '/'. Use this to override the
+# default substitution pattern.
+# VERSION: Version of the qml module
+# NAME: Override for the default import name used in the ${target}_qmltypes
# target (optional)
+# RESOURCE_PREFIX: Resource import prefix to be prepended to the module's
+# target path.
# QML_PLUGINDUMP_DEPENDENCIES: Path to a dependencies.json file to be consumed
# with the ${target}_qmltypes target (optional)
#
function(add_qml_module target)
+
set(qml_module_optional_args
+ CPP_PLUGIN
EMBED_QML_FILES
INSTALL_QML_FILES
)
set(qml_module_single_args
+ URI
TARGET_PATH
- IMPORT_VERSION
- IMPORT_NAME
+ VERSION
+ NAME
+ RESOURCE_PREFIX
QML_PLUGINDUMP_DEPENDENCIES
)
- set(qml_module_multi_args
- QML_FILES
- )
qt_parse_all_arguments(arg "add_qml_module"
"${__add_qt_plugin_optional_args};${qml_module_optional_args}"
"${__add_qt_plugin_single_args};${qml_module_single_args}"
- "${__add_qt_plugin_multi_args};${qml_module_multi_args}" ${ARGN})
+ "${__add_qt_plugin_multi_args}" ${ARGN})
- if (NOT arg_TARGET_PATH)
- message(FATAL_ERROR "add_qml_module called without specifying the module's target path. Please specify one using the TARGET_PATH parameter.")
+ if (NOT arg_URI)
+ message(FATAL_ERROR "add_qml_module called without specifying the module's uri. Please specify one using the URI parameter.")
endif()
set(target_path ${arg_TARGET_PATH})
- if (NOT arg_IMPORT_VERSION)
- message(FATAL_ERROR "add_qml_module called without specifying the module's import version. Please specify one using the IMPORT_VERSION parameter.")
+ if (NOT arg_VERSION)
+ message(FATAL_ERROR "add_qml_module called without specifying the module's import version. Please specify one using the VERSION parameter.")
endif()
- if (NOT arg_EMBED_QML_FILES AND NOT arg_INSTALL_QML_FILES)
- message(FATAL_ERROR "add_qml_module called without EMBED_QML_FILES or INSTALL_QML_FILES. Please specify at least one of these options.")
+ if (NOT arg_RESOURCE_PREFIX)
+ message(FATAL_ERROR "add_qml_module called without specifying the module's import prefix. Prease specify one using the RESOURCE_PREFIX parameter.")
+ endif()
+
+ if (NOT arg_TARGET_PATH)
+ string(REPLACE "." "/" arg_TARGET_PATH ${arg_URI})
endif()
qt_remove_args(plugin_args
@@ -1983,46 +2082,36 @@ function(add_qml_module target)
# If we have no sources, but qml files, create a custom target so the
# qml file will be visibile in an IDE.
- if (NOT arg_SOURCES AND arg_QML_FILES)
+ if (NOT arg_CPP_PLUGIN)
add_custom_target(${target}
SOURCES ${arg_QML_FILES}
)
- if (arg_EMBED_QML_FILES)
- message(FATAL_ERROR "Can't embed qml files in a qml module which does not have any c++ source files.")
- endif()
else()
add_qt_plugin(${target}
TYPE
qml_plugin
QML_TARGET_PATH
- "${target_path}"
- ${plugin_args}
+ "${arg_TARGET_PATH}"
+ ${plugin_args}
)
endif()
- foreach (qml_file IN LISTS arg_QML_FILES)
- if (NOT ${qml_file} MATCHES "\.js$"
- AND NOT ${qml_file} MATCHES "\.mjs$"
- AND NOT ${qml_file} MATCHES "\.qml$")
- message(FATAL_ERROR "add_qml_module, '${qml_file}' is not a valid qml file. Valid extensions are: .js, .mjs and .qml.")
- endif()
- endforeach()
-
- # Only generate compiled caches if we are not embedding
- if (arg_INSTALL_QML_FILES AND arg_QML_FILES AND NOT arg_EMBED_QML_FILES)
- add_qmlcachegen_target(${target}
- TARGET_PATH ${arg_TARGET_PATH}
- QML_FILES ${arg_QML_FILES}
- )
- endif()
+ # Set target properties
+ set_target_properties(${target}
+ PROPERTIES
+ QT_QML_MODULE_TARGET_PATH ${arg_TARGET_PATH}
+ QT_QML_MODULE_URI ${arg_URI}
+ QT_QML_MODULE_RESOURCE_PREFIX ${arg_RESOURCE_PREFIX}
+ QT_QML_MODULE_VERSION ${arg_VERSION}
+ )
qt_add_qmltypes_target(${target}
- TARGET_PATH "${target_path}"
- IMPORT_VERSION "${arg_IMPORT_VERSION}"
- IMPORT_NAME "${arg_IMPORT_NAME}"
+ TARGET_PATH "${arg_TARGET_PATH}"
+ IMPORT_VERSION "${arg_VERSION}"
+ IMPORT_NAME "${arg_NAME}"
QML_PLUGINDUMP_DEPENDENCIES "${arg_QML_PLUGINDUMP_DEPENDENCIES}")
- qt_path_join(qml_module_install_dir ${QT_INSTALL_DIR} "${INSTALL_QMLDIR}/${target_path}")
+ qt_path_join(qml_module_install_dir ${QT_INSTALL_DIR} "${INSTALL_QMLDIR}/${arg_TARGET_PATH}")
set(plugin_types "${CMAKE_CURRENT_SOURCE_DIR}/plugins.qmltypes")
if (EXISTS ${plugin_types})
qt_copy_or_install(FILES ${plugin_types}
@@ -2033,50 +2122,34 @@ function(add_qml_module target)
# plugin.qmltypes when present should also be copied to the
# cmake binary dir when doing prefix builds
file(COPY ${plugin_types}
- DESTINATION "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${target_path}"
+ DESTINATION "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${arg_TARGET_PATH}"
)
endif()
endif()
+ if (NOT QT_BUILD_SHARED_LIBS)
+ # only embed qmldir on static builds. Some qml modules may request
+ # their qml files to be embedded into their binary
+ string(REPLACE "." "_" qmldir_resource_name ${arg_URI})
+ set(qmldir_resource_name "${qmldir_resource_name}_qmldir")
+ add_qt_resource(${target} ${uri_target}
+ FILES "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
+ PREFIX "${arg_RESOURCE_PREFIX}/${arg_TARGET_PATH}"
+ )
+ endif()
+
qt_copy_or_install(
FILES
"${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
DESTINATION
"${qml_module_install_dir}"
)
+
if(QT_WILL_INSTALL)
# qmldir should also be copied to the cmake binary dir when doing
# prefix builds
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
- DESTINATION "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${target_path}"
- )
- endif()
-
- if(NOT QT_BUILD_SHARED_LIBS OR arg_EMBED_QML_FILES)
- string(REPLACE "/" "." uri ${arg_TARGET_PATH})
- string(REPLACE "." "_" uri_target ${uri})
- # only embed qmldir on static builds. Some qml modules may request
- # their qml files to be embedded into their binary
- if (NOT QT_BUILD_SHARED_LIBS)
- list(APPEND resource_files "${CMAKE_CURRENT_SOURCE_DIR}/qmldir")
- endif()
-
- if (resource_files)
- add_qt_resource(${target} ${uri_target}
- FILES ${resource_files}
- PREFIX "/qt-project.org/import/${target_path}"
- )
- endif()
-
- add_quick_compiler_target(${target}
- TARGET_PATH ${arg_TARGET_PATH}
- QML_FILES ${arg_QML_FILES}
- )
- endif()
-
- if (QT_BUILD_SHARED_LIBS AND arg_QML_FILES AND arg_INSTALL_QML_FILES)
- qt_copy_or_install(FILES ${arg_QML_FILES}
- DESTINATION "${qml_module_install_dir}"
+ DESTINATION "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${arg_TARGET_PATH}"
)
endif()
diff --git a/cmake/QtProperties.cmake b/cmake/QtProperties.cmake
index 0c3507b953..5cc8ca7b11 100644
--- a/cmake/QtProperties.cmake
+++ b/cmake/QtProperties.cmake
@@ -59,3 +59,38 @@ define_property(GLOBAL
""
)
+define_property(TARGET
+ PROPERTY
+ QT_QML_MODULE_TARGET_PATH
+ BRIEF_DOCS
+ "Specifies the target path for a qml module"
+ FULL_DOCS
+ "Specifies the target path for a qml module"
+)
+
+define_property(TARGET
+ PROPERTY
+ QT_QML_MODULE_URI
+ BRIEF_DOCS
+ "Specifies the URI for a qml module"
+ FULL_DOCS
+ "Specifies the URI for a qml module"
+)
+
+define_property(TARGET
+ PROPERTY
+ QT_QML_MODULE_RESOURCE_PREFIX
+ BRIEF_DOCS
+ "Specifies the qml module's resource prefix."
+ FULL_DOCS
+ "Specifies the qml module's resource prefix."
+)
+
+define_property(TARGET
+ PROPERTY
+ QT_QML_MODULE_VERSION
+ BRIEF_DOCS
+ "Specifies the qml module's version."
+ FULL_DOCS
+ "Specifies the qml module's version."
+)
diff --git a/util/cmake/pro2cmake.py b/util/cmake/pro2cmake.py
index 80c975cec1..a62b094ee9 100755
--- a/util/cmake/pro2cmake.py
+++ b/util/cmake/pro2cmake.py
@@ -651,8 +651,8 @@ class Scope(object):
return self._evalOps(key, None, [], inherit=inherit)
- def get_string(self, key: str, default: str = '') -> str:
- v = self.get(key)
+ def get_string(self, key: str, default: str = '', inherit : bool = False) -> str:
+ v = self.get(key, inherit = inherit)
if len(v) == 0:
return default
assert len(v) == 1
@@ -1646,6 +1646,8 @@ def write_main_part(cm_fh: typing.IO[str], name: str, typename: str,
# Evaluate total condition of all scopes:
recursive_evaluate_scope(scope)
+ is_qml_plugin = any('qml_plugin' == s for s in scope.get('_LOADED'))
+
if 'exceptions' in scope.get('CONFIG'):
extra_lines.append('EXCEPTIONS')
@@ -1706,6 +1708,9 @@ def write_main_part(cm_fh: typing.IO[str], name: str, typename: str,
write_android_part(cm_fh, name, scopes[0], indent)
+ if is_qml_plugin:
+ write_qml_plugin_qml_files(cm_fh, name, scopes[0], indent)
+
ignored_keys_report = write_ignored_keys(scopes[0], spaces(indent))
if ignored_keys_report:
cm_fh.write(ignored_keys_report)
@@ -1898,6 +1903,7 @@ def write_plugin(cm_fh, scope, *, indent: int = 0):
write_main_part(cm_fh, plugin_name, 'Plugin', plugin_function_name, scope,
indent=indent, extra_lines=extra, known_libraries={}, extra_keys=[])
+
def write_qml_plugin(cm_fh: typing.IO[str],
target: str,
scope: Scope, *,
@@ -1908,36 +1914,67 @@ def write_qml_plugin(cm_fh: typing.IO[str],
indent += 2
scope_config = scope.get('CONFIG')
is_embedding_qml_files = False
- if 'builtin_resources' in scope_config or 'qt_quick_compiler' in scope_config:
- extra_lines.append('EMBED_QML_FILES')
- is_embedding_qml_files = True
- if not is_embedding_qml_files:
- extra_lines.append('INSTALL_QML_FILES')
- if 'install_qml_files' in scope_config and is_embedding_qml_files:
- extra_lines.append('INSTALL_QML_FILES')
+ sources = scope.get_files('SOURCES')
+ if len(sources) != 0:
+ extra_lines.append('CPP_PLUGIN')
target_path = scope.get_string('TARGETPATH')
if target_path:
- extra_lines.append('TARGET_PATH "{}"'.format(target_path))
+ uri = target_path.replace('/','.')
+ extra_lines.append('URI "{}"'.format(uri))
+ # Catch special cases such as foo.QtQuick.2.bar, which when converted
+ # into a target path via cmake will result in foo/QtQuick/2/bar, which is
+ # not what we want. So we supply the target path override.
+ target_path_from_uri = uri.replace('.', '/')
+ if target_path != target_path_from_uri:
+ extra_lines.append('TARGET_PATH "{}"'.format(target_path))
+
import_version = scope.get_string('IMPORT_VERSION')
if import_version:
import_version = import_version.replace("$$QT_MINOR_VERSION","${CMAKE_PROJECT_VERSION_MINOR}")
- extra_lines.append('IMPORT_VERSION "{}"'.format(import_version))
+ extra_lines.append('VERSION "{}"'.format(import_version))
+
import_name = scope.get_string('IMPORT_NAME')
if import_name:
- extra_lines.append('IMPORT_NAME "{}"'.format(import_name))
+ extra_lines.append('NAME "{}"'.format(import_name))
plugindump_dep = scope.get_string('QML_PLUGINDUMP_DEPENDENCIES')
+
if plugindump_dep:
extra_lines.append('QML_PLUGINDUMP_DEPENDENCIES "{}"'.format(plugindump_dep))
+ # This is only required because of qmldir
+ extra_lines.append('RESOURCE_PREFIX "/qt-project.org/imports"')
+
+def write_qml_plugin_qml_files(cm_fh: typing.IO[str],
+ target: str,
+ scope: Scope,
+ indent: int = 0):
+
qml_files = scope.get_files('QML_FILES', use_vpath=True)
if qml_files:
- extra_lines.append('QML_FILES\n{}{}'.format(
+ target_path = scope.get_string('TARGETPATH', inherit=True)
+ target_path_mangled = target_path.replace('/', '_')
+ target_path_mangled = target_path_mangled.replace('.', '_')
+ resource_name = 'qmake_' + target_path_mangled
+ prefix = '/qt-project.org/imports/' + target_path
+ cm_fh.write('\n# QML Files\n')
+ cm_fh.write('{}add_qt_resource({} {}\n{}PREFIX\n{}"{}"\n{}FILES\n{}{}\n)\n'.format(
spaces(indent),
- '\n{}'.format(spaces(indent)).join(qml_files)))
-
+ target,
+ resource_name,
+ spaces(indent + 1),
+ spaces(indent + 2),
+ prefix,
+ spaces(indent + 1),
+ spaces(indent + 2),
+ '\n{}'.format(spaces(indent + 2)).join(qml_files)))
+
+ if 'install_qml_files' in scope.get('CONFIG'):
+ cm_fh.write('\nqt_install_qml_files({}\n FILES\n {}\n)\n\n'.format(
+ target,
+ '\n '.join(qml_files)))
def handle_app_or_lib(scope: Scope, cm_fh: typing.IO[str], *,