summaryrefslogtreecommitdiff
path: root/mesonbuild/modules
diff options
context:
space:
mode:
authorPierre Lamot <pierre@videolabs.io>2024-05-30 18:28:43 +0200
committerPierre Lamot <pierre@videolabs.io>2025-01-08 09:50:51 +0100
commit4508622a34932d23e336392a8a3c71ed79af4e3f (patch)
treef0552dd27d0e7f2b8381fbd301574a09f5edcf3e /mesonbuild/modules
parent7c68090a33cdf3e8cc96ee98529da89756c014e4 (diff)
downloadmeson-4508622a34932d23e336392a8a3c71ed79af4e3f.tar.gz
qt module: provide qml_module
This aims to bring the support of QML modules to meson, the goal is to provide something similar to CMake `qt_add_qml_module` function provided by Qt (see https://doc.qt.io/qt-6/qt-add-qml-module.html ) Fixes: #6988, #9683
Diffstat (limited to 'mesonbuild/modules')
-rw-r--r--mesonbuild/modules/_qt.py531
1 files changed, 526 insertions, 5 deletions
diff --git a/mesonbuild/modules/_qt.py b/mesonbuild/modules/_qt.py
index c37b1034d..7d52842f9 100644
--- a/mesonbuild/modules/_qt.py
+++ b/mesonbuild/modules/_qt.py
@@ -8,16 +8,17 @@ import os
import shutil
import typing as T
import xml.etree.ElementTree as ET
+import re
from . import ModuleReturnValue, ExtensionModule
from .. import build
from .. import options
from .. import mlog
from ..dependencies import find_external_dependency, Dependency, ExternalLibrary, InternalDependency
-from ..mesonlib import MesonException, File, version_compare, Popen_safe
+from ..mesonlib import MesonException, File, FileMode, version_compare, Popen_safe
from ..interpreter import extract_required_kwarg
from ..interpreter.type_checking import INSTALL_DIR_KW, INSTALL_KW, NoneType
-from ..interpreterbase import ContainerTypeInfo, FeatureDeprecated, KwargInfo, noPosargs, FeatureNew, typed_kwargs
+from ..interpreterbase import ContainerTypeInfo, FeatureDeprecated, KwargInfo, noPosargs, FeatureNew, typed_kwargs, typed_pos_args
from ..programs import NonExistingExternalProgram
if T.TYPE_CHECKING:
@@ -83,7 +84,7 @@ if T.TYPE_CHECKING:
class HasToolKwArgs(kwargs.ExtractRequired):
method: str
- tools: T.List[Literal['moc', 'uic', 'rcc', 'lrelease']]
+ tools: T.List[Literal['moc', 'uic', 'rcc', 'lrelease', 'qmlcachegen', 'qmltyperegistrar']]
class CompileTranslationsKwArgs(TypedDict):
@@ -95,6 +96,88 @@ if T.TYPE_CHECKING:
rcc_extra_arguments: T.List[str]
ts_files: T.List[T.Union[str, File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]]
+ class GenQrcKwArgs(TypedDict):
+
+ sources: T.Sequence[File]
+ aliases: T.Sequence[str]
+ prefix: str
+ output: str
+
+ class GenQmldirKwArgs(TypedDict):
+
+ module_name: str
+ module_version: str
+ module_prefix: str
+ qml_sources: T.Sequence[T.Union[FileOrString, build.GeneratedTypes]]
+ qml_singletons: T.Sequence[T.Union[FileOrString, build.GeneratedTypes]]
+ qml_internals: T.Sequence[T.Union[FileOrString, build.GeneratedTypes]]
+ designer_supported: bool
+ imports: T.List[str]
+ optional_imports: T.List[str]
+ default_imports: T.List[str]
+ depends_imports: T.List[str]
+ typeinfo: str
+ output: str
+
+ class GenQmlCachegenKwArgs(TypedDict):
+
+ target_name: str
+ qml_sources: T.Sequence[T.Union[FileOrString, build.GeneratedTypes]]
+ qml_qrc: T.Union[FileOrString, build.GeneratedTypes]
+ extra_args: T.List[str]
+ module_prefix: str
+ method: str
+
+ class GenQmlTypeRegistrarKwArgs(TypedDict):
+
+ target_name: str
+ import_name: str
+ major_version: str
+ minor_version: str
+ namespace: str
+ typeinfo: str
+ generate_qmltype: bool
+ collected_json: T.Optional[T.Union[FileOrString, build.CustomTarget]]
+ extra_args: T.List[str]
+ method: str
+ install: bool
+ install_dir: T.Optional[str]
+
+ class MocJsonCollectKwArgs(TypedDict):
+
+ target_name: str
+ moc_json: T.Sequence[build.GeneratedList]
+ method: str
+
+ class QmlModuleKwArgs(TypedDict):
+
+ version: str
+ qml_sources: T.List[T.Union[FileOrString, build.GeneratedTypes]]
+ qml_singletons: T.List[T.Union[FileOrString, build.GeneratedTypes]]
+ qml_internals: T.List[T.Union[FileOrString, build.GeneratedTypes]]
+ resources_prefix: str
+ moc_headers: T.List[T.Union[FileOrString, build.GeneratedTypes]]
+ include_directories: T.List[T.Union[str, build.IncludeDirs]]
+ imports: T.List[str]
+ optional_imports: T.List[str]
+ default_imports: T.List[str]
+ depends_imports: T.List[str]
+ designer_supported: bool
+ namespace: str
+ typeinfo: str
+ moc_extra_arguments: T.List[str]
+ rcc_extra_arguments: T.List[str]
+ qmlcachegen_extra_arguments: T.List[str]
+ qmltyperegistrar_extra_arguments: T.List[str]
+ generate_qmldir: bool
+ generate_qmltype: bool
+ cachegen: bool
+ dependencies: T.List[T.Union[Dependency, ExternalLibrary]]
+ method: str
+ preserve_paths: bool
+ install_dir: str
+ install: bool
+
def _list_in_set_validator(choices: T.Set[str]) -> T.Callable[[T.List[str]], T.Optional[str]]:
"""Check that the choice given was one of the given set."""
def inner(checklist: T.List[str]) -> T.Optional[str]:
@@ -105,12 +188,20 @@ def _list_in_set_validator(choices: T.Set[str]) -> T.Callable[[T.List[str]], T.O
return inner
+#While Qt recomment module name to a be dot separated alphanum, it can technically be
+#any well-formed ECMAScript Identifier Name.
+#As best effort here we just check for illegal characters
+#see https://doc.qt.io/qt-6/qtqml-modules-identifiedmodules.html
+_MODULE_NAME_PUNCT = r'- {}<>()[\].:;~%?&,+^=|!\/*"\''
+_MODULE_NAME_RE = f'[^{_MODULE_NAME_PUNCT}0-9][^{_MODULE_NAME_PUNCT}]*(\\.[^{_MODULE_NAME_PUNCT}0-9][^{_MODULE_NAME_PUNCT}]*)*'
+
class QtBaseModule(ExtensionModule):
_tools_detected = False
_rcc_supports_depfiles = False
_moc_supports_depfiles = False
- _set_of_qt_tools = {'moc', 'uic', 'rcc', 'lrelease'}
+ _set_of_qt_tools = {'moc', 'uic', 'rcc', 'lrelease', 'qmlcachegen', 'qmltyperegistrar'}
_moc_supports_json = False
+ _support_qml_module = False
def __init__(self, interpreter: Interpreter, qt_version: int = 5):
ExtensionModule.__init__(self, interpreter)
@@ -127,6 +218,7 @@ class QtBaseModule(ExtensionModule):
'compile_resources': self.compile_resources,
'compile_ui': self.compile_ui,
'compile_moc': self.compile_moc,
+ 'qml_module': self.qml_module,
})
def compilers_detect(self, state: ModuleState, qt_dep: QtDependencyType) -> None:
@@ -183,6 +275,9 @@ class QtBaseModule(ExtensionModule):
if qt.found():
# Get all tools and then make sure that they are the right version
self.compilers_detect(state, qt)
+ if version_compare(qt.version, '>=6.2.0'):
+ #5.1x supports qmlcachegen and other tools to some extend, but arguments/build process marginally differs
+ self._support_qml_module = True
if version_compare(qt.version, '>=5.15.0'):
self._moc_supports_depfiles = True
self._moc_supports_json = True
@@ -486,7 +581,7 @@ class QtBaseModule(ExtensionModule):
# depfile arguments (defaults to <output-name>.d)
DEPFILE_ARGS: T.List[str] = ['--output-dep-file'] if self._moc_supports_depfiles else []
- JSON_ARGS: T.List[str] = ['--output-json'] if do_output_json else []
+ JSON_ARGS: T.List[str] = ['--output-json'] if do_output_json else []
arguments = kwargs['extra_args'] + DEPFILE_ARGS + JSON_ARGS + inc + compile_args + ['@INPUT@', '-o', '@OUTPUT0@']
preserve_path_from = os.path.join(state.source_root, state.subdir) if kwargs['preserve_paths'] else None
@@ -649,3 +744,429 @@ class QtBaseModule(ExtensionModule):
return ModuleReturnValue(results.return_value[0], [results.new_objects, translations])
else:
return ModuleReturnValue(translations, [translations])
+
+ def _source_to_files(self, state: ModuleState, sources: T.Sequence[T.Union[FileOrString, build.GeneratedTypes]]) -> T.List[File]:
+
+ content_files = []
+ for s in sources:
+ if isinstance(s, (build.CustomTarget, build.CustomTargetIndex)):
+ for o in s.get_outputs():
+ content_files.append(File.from_built_file(state.backend.get_target_dir(s), o))
+ elif isinstance(s, File):
+ content_files.append(s)
+ elif isinstance(s, build.GeneratedList):
+ for gen_src in s.get_outputs():
+ content_files.append(File.from_built_file(state.subdir, gen_src))
+ else:
+ content_files.append(File.from_source_file(
+ state.environment.get_source_dir(),
+ state.subdir,
+ s
+ ))
+ return content_files
+
+ def _gen_qrc(self, state: ModuleState, kwargs: GenQrcKwArgs) -> File:
+
+ fileout = File.from_built_file(state.subdir, kwargs['output'])
+ fileout_abs = os.path.join(state.environment.build_dir, fileout.relative_name())
+ if not os.path.isdir(state.environment.build_dir):
+ os.mkdir(state.environment.build_dir)
+
+ rcc = ET.Element('RCC')
+ qresource = ET.SubElement(rcc, 'qresource', prefix='/' + kwargs['prefix'])
+ assert (len(kwargs['sources']) == len(kwargs['aliases']))
+ for source, alias in zip(kwargs['sources'], kwargs['aliases']):
+ filenode = ET.SubElement(qresource, 'file', alias=alias)
+ filenode.text = source.absolute_path(
+ state.environment.get_source_dir(),
+ state.environment.get_build_dir()
+ )
+
+ tree = ET.ElementTree(rcc)
+ tree.write(fileout_abs)
+ return fileout
+
+ def _gen_qmldir(self, state: ModuleState, kwargs: GenQmldirKwArgs) -> File:
+ module_name: str = kwargs['module_name']
+ module_version: str = kwargs['module_version']
+ module_prefix: str = kwargs['module_prefix']
+ designer_supported: bool = kwargs['designer_supported']
+ typeinfo_file: str = kwargs['typeinfo']
+
+ #Foo.Bar/1.0 foo.bar/auto foo.bar
+ import_re = re.compile(r'^(' + _MODULE_NAME_RE + r')(/((\d+(\.\d+)?)|auto))?$')
+
+ fileout = File.from_built_file(state.subdir, kwargs['output'])
+ fileout_abs = os.path.join(state.environment.build_dir, fileout.relative_name())
+ if not os.path.isdir(state.environment.build_dir):
+ os.mkdir(state.environment.build_dir)
+
+ with open(fileout_abs, 'w', encoding='utf-8') as fd:
+
+ def __gen_import(import_type: str, importlist: T.Sequence[str]) -> None:
+ for import_string in importlist:
+ match = import_re.match(import_string)
+ if not match:
+ raise MesonException(f'invalid syntax for qml import {import_string}')
+ module: str = match.group(1)
+ version: str = match.group(4) or ''
+ fd.write(f'{import_type} {module} {version}\n')
+
+ def __gen_declaration(qualifier: str, version: str, importlist: T.Sequence[T.Union[FileOrString, build.GeneratedTypes]]) -> None:
+ importpathlist = self._source_to_files(state, importlist)
+ for s in importpathlist:
+ basename: str = os.path.basename(s.fname)
+ classname: str = basename.rsplit('.', maxsplit=1)[0]
+
+ if not basename.endswith(('.qml', '.js', '.mjs')):
+ raise MesonException(f'unexpected file type declared in qml sources {s}')
+
+ if not classname or '.' in classname or classname[0].islower():
+ raise MesonException(f'{basename} is not a valid QML file name')
+ if version:
+ fd.write(f'{qualifier}{classname} {version} {basename}\n')
+ else:
+ fd.write(f'{qualifier}{classname} {basename}\n')
+
+ fd.write(f'module {module_name}\n')
+ fd.write(f'prefer :/{module_prefix}/\n')
+
+ __gen_import('import', kwargs['imports'])
+ __gen_import('optional import', kwargs['optional_imports'])
+ __gen_import('default import', kwargs['default_imports'])
+ __gen_import('depends', kwargs['depends_imports'])
+ __gen_declaration('', module_version, kwargs['qml_sources'])
+ __gen_declaration('singleton ', module_version, kwargs['qml_singletons'])
+ __gen_declaration('internal ', '', kwargs['qml_internals'])
+
+ if typeinfo_file:
+ fd.write(f'typeinfo {typeinfo_file}\n')
+
+ if designer_supported:
+ fd.write('designersupported\n')
+ return fileout
+
+ def _moc_json_collect(self, state: ModuleState, kwargs: MocJsonCollectKwArgs) -> build.CustomTarget:
+ self._detect_tools(state, kwargs['method'])
+ if not self.tools['moc'].found():
+ raise MesonException('qt.qml_module: ' +
+ self.tools['moc'].name + ' not found')
+
+ target_name: str = kwargs['target_name']
+ moc_json: T.Sequence[build.GeneratedList] = kwargs['moc_json']
+
+ #there may be a better way :-/
+ input_args: T.List[str] = []
+ input_counter = 0
+ for g in moc_json:
+ for fname in g.get_outputs():
+ if fname.endswith('.json'):
+ input_args.append(f'@INPUT{input_counter}@')
+ input_counter += 1
+
+ return build.CustomTarget(
+ f'moc_collect_json_{target_name}',
+ state.subdir,
+ state.subproject,
+ state.environment,
+ self.tools['moc'].get_command() + ['--collect-json', '-o', '@OUTPUT@'] + input_args,
+ moc_json,
+ [f'{target_name}_json_collect.json'],
+ description=f'Collecting json type information for {target_name}',
+ )
+
+ def _gen_qml_cachegen(self, state: ModuleState, kwargs: GenQmlCachegenKwArgs) -> T.List[T.Union[build.CustomTarget, build.GeneratedList]]:
+ self._detect_tools(state, kwargs['method'])
+ if not self.tools['qmlcachegen'].found():
+ raise MesonException('qt.qml_module: ' +
+ self.tools['qmlcachegen'].name + ' not found')
+
+ target_name: str = kwargs['target_name']
+
+ command_args = ['-o', '@OUTPUT@'] + kwargs['extra_args']
+ for qrc in self._source_to_files(state, [kwargs['qml_qrc']]):
+ command_args.extend(['--resource', qrc.absolute_path(
+ state.environment.get_source_dir(),
+ state.environment.get_build_dir()
+ )])
+
+ command_args.append('@INPUT@')
+
+ cache_gen = build.Generator(
+ self.tools['qmlcachegen'],
+ command_args,
+ [f'{target_name}_@BASENAME@.cpp'],
+ name=f'Qml cache generation for {target_name}')
+
+ output: T.List[T.Union[build.CustomTarget, build.GeneratedList]] = []
+ output.append(cache_gen.process_files(kwargs['qml_sources'], state))
+
+ cachegen_inputs: T.List[str] = []
+ qml_sources_paths = self._source_to_files(state, kwargs['qml_sources'])
+ for s in qml_sources_paths:
+ source_basename = os.path.basename(s.fname)
+ ressource_path = os.path.join('/', kwargs['module_prefix'], source_basename)
+ cachegen_inputs.append(ressource_path)
+
+ cacheloader_target = build.CustomTarget(
+ f'cacheloader_{target_name}',
+ state.subdir,
+ state.subproject,
+ state.environment,
+ self.tools['qmlcachegen'].get_command() + ['-o', '@OUTPUT@'] + ['--resource-name', f'qmlcache_{target_name}'] + kwargs['extra_args'] + ['--resource=@INPUT@'] + cachegen_inputs,
+ [kwargs['qml_qrc']],
+ #output name format matters here
+ [f'{target_name}_qmlcache_loader.cpp'],
+ description=f'Qml cache loader for {target_name}',
+ )
+ output.append(cacheloader_target)
+ return output
+
+ def _qml_type_registrar(self, state: ModuleState, kwargs: GenQmlTypeRegistrarKwArgs) -> build.CustomTarget:
+ self._detect_tools(state, kwargs['method'])
+ if not self.tools['qmltyperegistrar'].found():
+ raise MesonException('qt.qml_module: ' +
+ self.tools['qmltyperegistrar'].name + ' not found')
+
+ import_name: str = kwargs['import_name']
+ major_version: str = kwargs['major_version']
+ minor_version: str = kwargs['minor_version']
+ namespace: str = kwargs['namespace']
+ typeinfo: str = kwargs['typeinfo']
+ target_name: str = kwargs['target_name']
+ collected_json: T.Optional[T.Union[FileOrString, build.CustomTarget]] = kwargs['collected_json']
+
+ inputs: T.Sequence[T.Union[FileOrString, build.CustomTarget]] = [collected_json] if collected_json else []
+ outputs: T.List[str] = [f'{target_name}_qmltyperegistrations.cpp']
+ install_dir: T.List[T.Union[str, Literal[False]]] = [False]
+ install_tag: T.List[T.Union[str, None]] = [None]
+
+ cmd = self.tools['qmltyperegistrar'].get_command() + [
+ '--import-name', import_name,
+ '--major-version', major_version,
+ '--minor-version', minor_version,
+ '-o', '@OUTPUT0@',
+ ]
+
+ cmd.extend(kwargs['extra_args'])
+
+ if namespace:
+ cmd.extend(['--namespace', namespace])
+
+ if kwargs['generate_qmltype']:
+ cmd.extend(['--generate-qmltypes', '@OUTPUT1@'])
+ if typeinfo == '':
+ outputs.append(f'{target_name}.qmltypes')
+ else:
+ outputs.append(f'{typeinfo}')
+ install_dir.append(kwargs['install_dir'])
+ install_tag.append('devel')
+
+ if collected_json:
+ cmd.append('@INPUT@')
+
+ return build.CustomTarget(
+ f'typeregistrar_{target_name}',
+ state.subdir,
+ state.subproject,
+ state.environment,
+ cmd,
+ inputs,
+ outputs,
+ install=kwargs['install'],
+ install_dir=install_dir,
+ install_tag=install_tag,
+ description=f'Qml type registration for {target_name}',
+ )
+
+ @FeatureNew('qt.qml_module', '1.7')
+ @typed_pos_args('qt.qml_module', str)
+ @typed_kwargs(
+ 'qt.qml_module',
+ KwargInfo('version', str, default='254.254'),
+ #qml sources
+ KwargInfo('qml_sources', ContainerTypeInfo(list, (File, str, build.CustomTarget)), listify=True, default=[]),
+ KwargInfo('qml_singletons', ContainerTypeInfo(list, (File, str, build.CustomTarget)), listify=True, default=[]),
+ KwargInfo('qml_internals', ContainerTypeInfo(list, (File, str, build.CustomTarget)), listify=True, default=[]),
+ KwargInfo('resources_prefix', str, default='qt/qml'),
+ #qmldir generation
+ KwargInfo('imports', ContainerTypeInfo(list, (str)), default=[]),
+ KwargInfo('optional_imports', ContainerTypeInfo(list, (str)), default=[]),
+ KwargInfo('default_imports', ContainerTypeInfo(list, (str)), default=[]),
+ #match DEPENDENCIES argument from CMake, but dependencies keyword is already taken
+ KwargInfo('depends_imports', ContainerTypeInfo(list, (str)), default=[]),
+ KwargInfo('designer_supported', bool, default=False),
+ #for type registration, same arguments as moc
+ #moc_sources is voluntary ommited as typeregistrar needs to import a header
+ KwargInfo('moc_headers', ContainerTypeInfo(list, (File, str, build.CustomTarget)), listify=True, default=[]),
+ KwargInfo('include_directories', ContainerTypeInfo(list, (build.IncludeDirs, str)), listify=True, default=[]),
+ KwargInfo('namespace', str, default=''),
+ KwargInfo('typeinfo', str, default=''),
+
+ KwargInfo('moc_extra_arguments', ContainerTypeInfo(list, str), listify=True, default=[]),
+ KwargInfo('rcc_extra_arguments', ContainerTypeInfo(list, str), listify=True, default=[]),
+ KwargInfo('qmlcachegen_extra_arguments', ContainerTypeInfo(list, str), listify=True, default=[]),
+ KwargInfo('qmltyperegistrar_extra_arguments', ContainerTypeInfo(list, str), listify=True, default=[]),
+
+ KwargInfo('generate_qmldir', bool, default=True),
+ KwargInfo('generate_qmltype', bool, default=True),
+ KwargInfo('cachegen', bool, default=True),
+
+ KwargInfo('dependencies', ContainerTypeInfo(list, (Dependency, ExternalLibrary)), listify=True, default=[]),
+ INSTALL_DIR_KW,
+ INSTALL_KW,
+ KwargInfo('method', str, default='auto'),
+ KwargInfo('preserve_paths', bool, default=False),
+ )
+ def qml_module(self, state: ModuleState, args: T.Tuple[str], kwargs: QmlModuleKwArgs) -> ModuleReturnValue:
+
+ self._detect_tools(state, kwargs['method'])
+ if not self._support_qml_module:
+ raise MesonException('qt.qml_module is not suppported for this version of Qt')
+
+ #Major.Minor(.Patch)
+ version_re = re.compile(r'^(\d+)\.(\d+)(\.(\d+))?$')
+ module_name_re = re.compile(_MODULE_NAME_RE)
+
+ output: T.List[T.Union[build.CustomTarget, build.GeneratedList]] = []
+
+ module_name: str = args[0]
+ if not module_name_re.fullmatch(module_name):
+ raise MesonException(f'qml module URI should be in the form Foo.Bar.xxx, got {module_name}')
+
+ module_version: str = kwargs['version']
+ module_version_match = version_re.match(module_version)
+ if not module_version_match:
+ raise MesonException(f'qml module version should be in the form Major.Minor, got {module_version}')
+ module_version_major: str = module_version_match.group(1)
+ module_version_minor: str = module_version_match.group(2)
+ #qt ignores .patch version
+ module_version_short = f'{module_version_major}.{module_version_minor}'
+
+ module_prefix_list: T.List[str] = module_name.split('.')
+ module_prefix: str = os.path.join(*module_prefix_list)
+ module_prefix_full: str = os.path.join(*(kwargs['resources_prefix'].split('/') + module_prefix_list))
+
+ #same format as the one derived from qmltyperegistrar
+ target_name = re.sub(r'[^A-Za-z0-9]', '_', module_name)
+
+ qrc_resouces: T.List[T.Union[FileOrString, build.GeneratedTypes]] = []
+ all_qml: T.Sequence[T.Union[FileOrString, build.GeneratedTypes]] = kwargs['qml_sources'] + kwargs['qml_singletons'] + kwargs['qml_internals']
+ all_qml_files: T.List[File] = self._source_to_files(state, all_qml)
+ all_qml_basename: T.List[str] = [os.path.basename(p.fname) for p in all_qml_files]
+
+ install_dir: str = kwargs['install_dir'] or 'qml'
+ module_install_dir: str = os.path.join(install_dir, module_prefix)
+
+ if len(all_qml) != 0:
+ qml_qrc_kwargs: GenQrcKwArgs = {
+ 'output': f'{target_name}_qml.qrc',
+ 'sources': all_qml_files,
+ 'aliases': all_qml_basename,
+ 'prefix': module_prefix_full,
+ }
+ qml_qrc = self._gen_qrc(state, qml_qrc_kwargs)
+
+ if not kwargs['cachegen']:
+ qrc_resouces.append(qml_qrc)
+ else:
+ cachegen_kwargs: GenQmlCachegenKwArgs = {
+ 'target_name': target_name,
+ 'qml_qrc': qml_qrc,
+ 'qml_sources': all_qml,
+ 'module_prefix': module_prefix_full,
+ 'extra_args': kwargs['qmlcachegen_extra_arguments'],
+ 'method': kwargs['method'],
+ }
+ output.extend(self._gen_qml_cachegen(state, cachegen_kwargs))
+
+ #copy QML files for Qt tools
+ if kwargs['install']:
+ self.interpreter.install_data_impl(all_qml_files, module_install_dir,
+ FileMode(), all_qml_basename, 'devel')
+
+ collected_json: T.Optional[T.Union[FileOrString, build.CustomTarget]] = None
+ if kwargs['moc_headers']:
+ compile_moc_kwargs: MocCompilerKwArgs = {
+ 'sources': [],
+ 'headers': kwargs['moc_headers'],
+ 'extra_args': kwargs['moc_extra_arguments'],
+ 'method': kwargs['method'],
+ 'include_directories': kwargs['include_directories'],
+ 'dependencies': kwargs['dependencies'],
+ 'preserve_paths': kwargs['preserve_paths'],
+ 'output_json': True,
+ }
+ moc_output = self._compile_moc_impl(state, compile_moc_kwargs)
+ output.extend(moc_output)
+
+ moc_collect_json_kwargs: MocJsonCollectKwArgs = {
+ 'target_name': target_name,
+ 'moc_json': moc_output,
+ 'method': kwargs['method'],
+ }
+ collected_json = self._moc_json_collect(state, moc_collect_json_kwargs)
+ output.append(collected_json)
+
+ typeinfo_file: str = ''
+ #cmake NO_GENERATE_QMLTYPE disable the whole type registration, not just the .qmltype generation
+ if kwargs['generate_qmltype']:
+ qmltyperegistrar_kwargs: GenQmlTypeRegistrarKwArgs = {
+ 'target_name': target_name,
+ 'import_name': module_name,
+ 'major_version': module_version_major,
+ 'minor_version': module_version_minor,
+ 'collected_json': collected_json,
+ 'namespace': kwargs['namespace'],
+ 'generate_qmltype': True,
+ 'extra_args': kwargs['qmltyperegistrar_extra_arguments'],
+ 'typeinfo': kwargs['typeinfo'],
+ 'method': kwargs['method'],
+ 'install': kwargs['install'],
+ 'install_dir': module_install_dir,
+ }
+ type_registrar_output = self._qml_type_registrar(state, qmltyperegistrar_kwargs)
+ output.append(type_registrar_output)
+ if len(type_registrar_output.get_outputs()) == 2:
+ typeinfo_file = type_registrar_output.get_outputs()[1]
+
+ if kwargs['generate_qmldir']:
+ qmldir_kwargs: GenQmldirKwArgs = {
+ 'output': f'{target_name}_qmldir',
+ 'module_name': module_name,
+ 'module_version': module_version_short,
+ 'qml_sources': kwargs['qml_sources'],
+ 'qml_singletons': kwargs['qml_singletons'],
+ 'qml_internals': kwargs['qml_internals'],
+ 'imports': kwargs['imports'],
+ 'optional_imports': kwargs['optional_imports'],
+ 'default_imports': kwargs['default_imports'],
+ 'depends_imports': kwargs['depends_imports'],
+ 'designer_supported': kwargs['designer_supported'],
+ 'typeinfo': typeinfo_file,
+ 'module_prefix': module_prefix_full,
+ }
+ qmldir_file: File = self._gen_qmldir(state, qmldir_kwargs)
+
+ qmldir_qrc_kwargs: GenQrcKwArgs = {
+ 'output': f'{target_name}_qmldir.qrc',
+ 'sources': self._source_to_files(state, [qmldir_file]),
+ 'aliases': ['qmldir'],
+ 'prefix': module_prefix_full,
+ }
+ qrc_resouces.append(self._gen_qrc(state, qmldir_qrc_kwargs))
+
+ if kwargs['install']:
+ self.interpreter.install_data_impl([qmldir_file], module_install_dir,
+ FileMode(), ['qmldir'], 'devel')
+
+ if qrc_resouces:
+ compile_resource_kwargs: ResourceCompilerKwArgs = {
+ 'name': target_name,
+ 'sources': qrc_resouces,
+ 'extra_args': kwargs['rcc_extra_arguments'],
+ 'method': kwargs['method'],
+ }
+ output.extend(self._compile_resources_impl(state, compile_resource_kwargs))
+
+ return ModuleReturnValue(output, [output])