aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/modules/qt.py
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2021-06-16 20:11:46 +0300
committerGitHub <noreply@github.com>2021-06-16 20:11:46 +0300
commit6fb2f86379c224e99652748eea94a03321b9bd11 (patch)
treea96fb2b8f6468d793b64b172abc67b8224e0edc3 /mesonbuild/modules/qt.py
parent537adce5d803ff4ae373d87671190a4a2682ff54 (diff)
parent0f5e55a749f0fed6330b216a82de941de3ccf9d6 (diff)
downloadmeson-6fb2f86379c224e99652748eea94a03321b9bd11.zip
meson-6fb2f86379c224e99652748eea94a03321b9bd11.tar.gz
meson-6fb2f86379c224e99652748eea94a03321b9bd11.tar.bz2
Merge pull request #8822 from dcbaker/submit/annotate-and-check-qt-module
Rewrite the Qt module for type safety!
Diffstat (limited to 'mesonbuild/modules/qt.py')
-rw-r--r--mesonbuild/modules/qt.py436
1 files changed, 311 insertions, 125 deletions
diff --git a/mesonbuild/modules/qt.py b/mesonbuild/modules/qt.py
index aecfe50..7d752db 100644
--- a/mesonbuild/modules/qt.py
+++ b/mesonbuild/modules/qt.py
@@ -1,4 +1,5 @@
# Copyright 2015 The Meson development team
+# Copyright © 2021 Intel Corporation
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -12,34 +13,95 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from mesonbuild.dependencies import find_external_dependency
import os
import shutil
import typing as T
+import xml.etree.ElementTree as ET
-from .. import mlog
+from . import ModuleReturnValue, ExtensionModule
from .. import build
from .. import mesonlib
-from ..mesonlib import MesonException, extract_as_list, File, unholder, version_compare
-from ..dependencies import Dependency
-import xml.etree.ElementTree as ET
-from . import ModuleReturnValue, ExtensionModule
-from ..interpreterbase import noPosargs, permittedKwargs, FeatureNew, FeatureNewKwargs
+from .. import mlog
+from ..dependencies import find_external_dependency
from ..interpreter import extract_required_kwarg
+from ..interpreter.interpreterobjects import DependencyHolder, ExternalLibraryHolder, IncludeDirsHolder, FeatureOptionHolder, GeneratedListHolder
+from ..interpreterbase import ContainerTypeInfo, FeatureDeprecated, KwargInfo, noPosargs, FeatureNew, typed_kwargs
+from ..mesonlib import MesonException, File
from ..programs import NonExistingExternalProgram
if T.TYPE_CHECKING:
+ from . import ModuleState
+ from ..dependencies.qt import QtPkgConfigDependency, QmakeQtDependency
from ..interpreter import Interpreter
- from ..dependencies.qt import QtBaseDependency
- from ..environment import Environment
+ from ..interpreter import kwargs
from ..programs import ExternalProgram
+ QtDependencyType = T.Union[QtPkgConfigDependency, QmakeQtDependency]
+
+ from typing_extensions import TypedDict
+
+ class ResourceCompilerKwArgs(TypedDict):
+
+ """Keyword arguments for the Resource Compiler method."""
+
+ name: T.Optional[str]
+ sources: T.List[mesonlib.FileOrString]
+ extra_args: T.List[str]
+ method: str
+
+ class UICompilerKwArgs(TypedDict):
+
+ """Keyword arguments for the Ui Compiler method."""
+
+ sources: T.List[mesonlib.FileOrString]
+ extra_args: T.List[str]
+ method: str
+
+ class MocCompilerKwArgs(TypedDict):
+
+ """Keyword arguments for the Moc Compiler method."""
+
+ sources: T.List[mesonlib.FileOrString]
+ headers: T.List[mesonlib.FileOrString]
+ extra_args: T.List[str]
+ method: str
+ include_directories: T.List[IncludeDirsHolder]
+ dependencies: T.List[T.Union[DependencyHolder, ExternalLibraryHolder]]
+
+ class PreprocessKwArgs(TypedDict):
+
+ sources: T.List[mesonlib.FileOrString]
+ moc_sources: T.List[mesonlib.FileOrString]
+ moc_headers: T.List[mesonlib.FileOrString]
+ qresources: T.List[mesonlib.FileOrString]
+ ui_files: T.List[mesonlib.FileOrString]
+ moc_extra_arguments: T.List[str]
+ rcc_extra_arguments: T.List[str]
+ uic_extra_arguments: T.List[str]
+ include_directories: T.List[IncludeDirsHolder]
+ dependencies: T.List[T.Union[DependencyHolder, ExternalLibraryHolder]]
+ method: str
+
+ class HasToolKwArgs(kwargs.ExtractRequired):
+
+ method: str
+
+ class CompileTranslationsKwArgs(TypedDict):
+
+ build_by_default: bool
+ install: bool
+ install_dir: T.Optional[str]
+ method: str
+ qresource: T.Optional[str]
+ rcc_extra_arguments: T.List[str]
+ ts_files: T.List[str]
+
class QtBaseModule(ExtensionModule):
- tools_detected = False
- rcc_supports_depfiles = False
+ _tools_detected = False
+ _rcc_supports_depfiles = False
- def __init__(self, interpreter: 'Interpreter', qt_version=5):
+ def __init__(self, interpreter: 'Interpreter', qt_version: int = 5):
ExtensionModule.__init__(self, interpreter)
self.qt_version = qt_version
self.moc: 'ExternalProgram' = NonExistingExternalProgram('moc')
@@ -50,9 +112,12 @@ class QtBaseModule(ExtensionModule):
'has_tools': self.has_tools,
'preprocess': self.preprocess,
'compile_translations': self.compile_translations,
+ 'compile_resources': self.compile_resources,
+ 'compile_ui': self.compile_ui,
+ 'compile_moc': self.compile_moc,
})
- def compilers_detect(self, state, qt_dep: 'QtBaseDependency') -> None:
+ def compilers_detect(self, state: 'ModuleState', qt_dep: 'QtDependencyType') -> None:
"""Detect Qt (4 or 5) moc, uic, rcc in the specified bindir or in PATH"""
# It is important that this list does not change order as the order of
# the returned ExternalPrograms will change as well
@@ -96,18 +161,19 @@ class QtBaseModule(ExtensionModule):
if p.found():
setattr(self, name, p)
- def _detect_tools(self, state, method, required=True):
- if self.tools_detected:
+ def _detect_tools(self, state: 'ModuleState', method: str, required: bool = True) -> None:
+ if self._tools_detected:
return
- self.tools_detected = True
+ self._tools_detected = True
mlog.log(f'Detecting Qt{self.qt_version} tools')
kwargs = {'required': required, 'modules': 'Core', 'method': method}
- qt = find_external_dependency(f'qt{self.qt_version}', state.environment, kwargs)
+ # Just pick one to make mypy happy
+ qt = T.cast('QtPkgConfigDependency', find_external_dependency(f'qt{self.qt_version}', state.environment, kwargs))
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, '>=5.14.0'):
- self.rcc_supports_depfiles = True
+ if mesonlib.version_compare(qt.version, '>=5.14.0'):
+ self._rcc_supports_depfiles = True
else:
mlog.warning('rcc dependencies will not work properly until you move to Qt >= 5.14:',
mlog.bold('https://bugreports.qt.io/browse/QTBUG-45460'), fatal=False)
@@ -118,21 +184,24 @@ class QtBaseModule(ExtensionModule):
self.rcc = NonExistingExternalProgram(name='rcc' + suffix)
self.lrelease = NonExistingExternalProgram(name='lrelease' + suffix)
- def qrc_nodes(self, state, rcc_file):
- if type(rcc_file) is str:
+ @staticmethod
+ def _qrc_nodes(state: 'ModuleState', rcc_file: 'mesonlib.FileOrString') -> T.Tuple[str, T.List[str]]:
+ abspath: str
+ if isinstance(rcc_file, str):
abspath = os.path.join(state.environment.source_dir, state.subdir, rcc_file)
rcc_dirname = os.path.dirname(abspath)
- elif type(rcc_file) is File:
+ else:
abspath = rcc_file.absolute_path(state.environment.source_dir, state.environment.build_dir)
rcc_dirname = os.path.dirname(abspath)
+ # FIXME: what error are we actually tring to check here?
try:
tree = ET.parse(abspath)
root = tree.getroot()
- result = []
+ result: T.List[str] = []
for child in root[0]:
if child.tag != 'file':
- mlog.warning("malformed rcc file: ", os.path.join(state.subdir, rcc_file))
+ mlog.warning("malformed rcc file: ", os.path.join(state.subdir, str(rcc_file)))
break
else:
result.append(child.text)
@@ -141,9 +210,9 @@ class QtBaseModule(ExtensionModule):
except Exception:
raise MesonException(f'Unable to parse resource file {abspath}')
- def parse_qrc_deps(self, state, rcc_file):
- rcc_dirname, nodes = self.qrc_nodes(state, rcc_file)
- result = []
+ def _parse_qrc_deps(self, state: 'ModuleState', rcc_file: 'mesonlib.FileOrString') -> T.List[File]:
+ rcc_dirname, nodes = self._qrc_nodes(state, rcc_file)
+ result: T.List[File] = []
for resource_path in nodes:
# We need to guess if the pointed resource is:
# a) in build directory -> implies a generated file
@@ -170,11 +239,18 @@ class QtBaseModule(ExtensionModule):
result.append(File(is_built=False, subdir=state.subdir, fname=path_from_rcc))
return result
- @noPosargs
- @permittedKwargs({'method', 'required'})
@FeatureNew('qt.has_tools', '0.54.0')
- def has_tools(self, state, args, kwargs):
+ @noPosargs
+ @typed_kwargs(
+ 'qt.has_tools',
+ KwargInfo('required', (bool, FeatureOptionHolder), default=False),
+ KwargInfo('method', str, default='auto'),
+ )
+ def has_tools(self, state: 'ModuleState', args: T.Tuple, kwargs: 'HasToolKwArgs') -> bool:
method = kwargs.get('method', 'auto')
+ # We have to cast here because TypedDicts are invariant, even though
+ # ExtractRequiredKwArgs is a subset of HasToolKwArgs, type checkers
+ # will insist this is wrong
disabled, required, feature = extract_required_kwarg(kwargs, state.subproject, default=False)
if disabled:
mlog.log('qt.has_tools skipped: feature', mlog.bold(feature), 'disabled')
@@ -187,117 +263,227 @@ class QtBaseModule(ExtensionModule):
return False
return True
- @FeatureNewKwargs('qt.preprocess', '0.49.0', ['uic_extra_arguments'])
- @FeatureNewKwargs('qt.preprocess', '0.44.0', ['moc_extra_arguments'])
- @FeatureNewKwargs('qt.preprocess', '0.49.0', ['rcc_extra_arguments'])
- @permittedKwargs({'moc_headers', 'moc_sources', 'uic_extra_arguments', 'moc_extra_arguments', 'rcc_extra_arguments', 'include_directories', 'dependencies', 'ui_files', 'qresources', 'method'})
- def preprocess(self, state, args, kwargs):
- rcc_files, ui_files, moc_headers, moc_sources, uic_extra_arguments, moc_extra_arguments, rcc_extra_arguments, sources, include_directories, dependencies \
- = [extract_as_list(kwargs, c, pop=True) for c in ['qresources', 'ui_files', 'moc_headers', 'moc_sources', 'uic_extra_arguments', 'moc_extra_arguments', 'rcc_extra_arguments', 'sources', 'include_directories', 'dependencies']]
- sources += args[1:]
- method = kwargs.get('method', 'auto')
- self._detect_tools(state, method)
- err_msg = "{0} sources specified and couldn't find {1}, " \
- "please check your qt{2} installation"
- if (moc_headers or moc_sources) and not self.moc.found():
- raise MesonException(err_msg.format('MOC', f'moc-qt{self.qt_version}', self.qt_version))
- if rcc_files:
- if not self.rcc.found():
- raise MesonException(err_msg.format('RCC', f'rcc-qt{self.qt_version}', self.qt_version))
+ @FeatureNew('qt.compile_resources', '0.59.0')
+ @noPosargs
+ @typed_kwargs(
+ 'qt.compile_resources',
+ KwargInfo('name', str),
+ KwargInfo('sources', ContainerTypeInfo(list, (File, str), allow_empty=False), listify=True, required=True),
+ KwargInfo('extra_args', ContainerTypeInfo(list, str), listify=True, default=[]),
+ KwargInfo('method', str, default='auto')
+ )
+ def compile_resources(self, state: 'ModuleState', args: T.Tuple, kwargs: 'ResourceCompilerKwArgs') -> ModuleReturnValue:
+ """Compile Qt resources files.
+
+ Uses CustomTargets to generate .cpp files from .qrc files.
+ """
+ self._detect_tools(state, kwargs['method'])
+ if not self.rcc.found():
+ err_msg = ("{0} sources specified and couldn't find {1}, "
+ "please check your qt{2} installation")
+ raise MesonException(err_msg.format('RCC', f'rcc-qt{self.qt_version}', self.qt_version))
+
+ # List of generated CustomTargets
+ targets: T.List[build.CustomTarget] = []
+
+ # depfile arguments
+ DEPFILE_ARGS: T.List[str] = ['--depfile', '@DEPFILE@'] if self._rcc_supports_depfiles else []
+
+ name = kwargs['name']
+ sources = kwargs['sources']
+ extra_args = kwargs['extra_args']
+
+ # If a name was set generate a single .cpp file from all of the qrc
+ # files, otherwise generate one .cpp file per qrc file.
+ if name:
+ qrc_deps: T.List[File] = []
+ for s in sources:
+ qrc_deps.extend(self._parse_qrc_deps(state, s))
+
+ rcc_kwargs: T.Dict[str, T.Any] = { # TODO: if CustomTarget had typing information we could use that here...
+ 'input': sources,
+ 'output': name + '.cpp',
+ 'command': self.rcc.get_command() + ['-name', name, '-o', '@OUTPUT@'] + extra_args + ['@INPUT@'] + DEPFILE_ARGS,
+ 'depend_files': qrc_deps,
+ 'depfile': f'{name}.d',
+ }
+ res_target = build.CustomTarget(name, state.subdir, state.subproject, rcc_kwargs)
+ targets.append(res_target)
+ else:
+ for rcc_file in sources:
+ qrc_deps = self._parse_qrc_deps(state, rcc_file)
+ if isinstance(rcc_file, str):
+ basename = os.path.basename(rcc_file)
+ else:
+ basename = os.path.basename(rcc_file.fname)
+ name = f'qt{self.qt_version}-{basename.replace(".", "_")}'
+ rcc_kwargs = {
+ 'input': rcc_file,
+ 'output': f'{name}.cpp',
+ 'command': self.rcc.get_command() + ['-name', '@BASENAME@', '-o', '@OUTPUT@'] + extra_args + ['@INPUT@'] + DEPFILE_ARGS,
+ 'depend_files': qrc_deps,
+ 'depfile': f'{name}.d',
+ }
+ res_target = build.CustomTarget(name, state.subdir, state.subproject, rcc_kwargs)
+ targets.append(res_target)
+
+ return ModuleReturnValue(targets, [targets])
+
+ @FeatureNew('qt.compile_ui', '0.59.0')
+ @noPosargs
+ @typed_kwargs(
+ 'qt.compile_ui',
+ KwargInfo('sources', ContainerTypeInfo(list, (File, str), allow_empty=False), listify=True, required=True),
+ KwargInfo('extra_args', ContainerTypeInfo(list, str), listify=True, default=[]),
+ KwargInfo('method', str, default='auto')
+ )
+ def compile_ui(self, state: 'ModuleState', args: T.Tuple, kwargs: 'ResourceCompilerKwArgs') -> ModuleReturnValue:
+ """Compile UI resources into cpp headers."""
+ self._detect_tools(state, kwargs['method'])
+ if not self.uic.found():
+ err_msg = ("{0} sources specified and couldn't find {1}, "
+ "please check your qt{2} installation")
+ raise MesonException(err_msg.format('UIC', f'uic-qt{self.qt_version}', self.qt_version))
+
+ # TODO: This generator isn't added to the generator list in the Interpreter
+ gen = build.Generator(
+ self.uic,
+ kwargs['extra_args'] + ['-o', '@OUTPUT@', '@INPUT@'],
+ ['ui_@BASENAME@.h'],
+ name=f'Qt{self.qt_version} ui')
+ out = GeneratedListHolder(gen.process_files(kwargs['sources'], state))
+ return ModuleReturnValue(out, [out])
+
+ @FeatureNew('qt.compile_moc', '0.59.0')
+ @noPosargs
+ @typed_kwargs(
+ 'qt.compile_moc',
+ KwargInfo('sources', ContainerTypeInfo(list, (File, str)), listify=True, default=[]),
+ KwargInfo('headers', ContainerTypeInfo(list, (File, str)), listify=True, default=[]),
+ KwargInfo('extra_args', ContainerTypeInfo(list, str), listify=True, default=[]),
+ KwargInfo('method', str, default='auto'),
+ KwargInfo('include_directories', ContainerTypeInfo(list, IncludeDirsHolder), listify=True, default=[]),
+ KwargInfo('dependencies', ContainerTypeInfo(list, (DependencyHolder, ExternalLibraryHolder)), listify=True, default=[]),
+ )
+ def compile_moc(self, state: 'ModuleState', args: T.Tuple, kwargs: 'MocCompilerKwArgs') -> ModuleReturnValue:
+ self._detect_tools(state, kwargs['method'])
+ if not self.moc.found():
+ err_msg = ("{0} sources specified and couldn't find {1}, "
+ "please check your qt{2} installation")
+ raise MesonException(err_msg.format('MOC', f'uic-qt{self.qt_version}', self.qt_version))
+
+ if not (kwargs['headers'] or kwargs['sources']):
+ raise build.InvalidArguments('At least one of the "headers" or "sources" keyword arguments must be provied and not empty')
+
+ inc = state.get_include_args(include_dirs=kwargs['include_directories'])
+ compile_args: T.List[str] = []
+ for dep in kwargs['dependencies']:
+ compile_args.extend([a for a in dep.held_object.get_all_compile_args() if a.startswith(('-I', '-D'))])
+
+ output: T.List[build.GeneratedList] = []
+
+ arguments = kwargs['extra_args'] + inc + compile_args + ['@INPUT@', '-o', '@OUTPUT@']
+ if kwargs['headers']:
+ moc_gen = build.Generator(
+ self.moc, arguments, ['moc_@BASENAME@.cpp'],
+ name=f'Qt{self.qt_version} moc header')
+ output.append(moc_gen.process_files(kwargs['headers'], state))
+ if kwargs['sources']:
+ moc_gen = build.Generator(
+ self.moc, arguments, ['@BASENAME@.moc'],
+ name=f'Qt{self.qt_version} moc source')
+ output.append(moc_gen.process_files(kwargs['sources'], state))
+
+ return ModuleReturnValue(output, [output])
+
+ # We can't use typed_pos_args here, the signature is ambiguious
+ @typed_kwargs(
+ 'qt.preprocess',
+ KwargInfo('sources', ContainerTypeInfo(list, (File, str)), listify=True, default=[], deprecated='0.59.0'),
+ KwargInfo('qresources', ContainerTypeInfo(list, (File, str)), listify=True, default=[]),
+ KwargInfo('ui_files', ContainerTypeInfo(list, (File, str)), listify=True, default=[]),
+ KwargInfo('moc_sources', ContainerTypeInfo(list, (File, str)), listify=True, default=[]),
+ KwargInfo('moc_headers', ContainerTypeInfo(list, (File, str)), listify=True, default=[]),
+ KwargInfo('moc_extra_arguments', ContainerTypeInfo(list, str), listify=True, default=[], since='0.44.0'),
+ KwargInfo('rcc_extra_arguments', ContainerTypeInfo(list, str), listify=True, default=[], since='0.49.0'),
+ KwargInfo('uic_extra_arguments', ContainerTypeInfo(list, str), listify=True, default=[], since='0.49.0'),
+ KwargInfo('method', str, default='auto'),
+ KwargInfo('include_directories', ContainerTypeInfo(list, IncludeDirsHolder), listify=True, default=[]),
+ KwargInfo('dependencies', ContainerTypeInfo(list, (DependencyHolder, ExternalLibraryHolder)), listify=True, default=[]),
+ )
+ def preprocess(self, state: 'ModuleState', args: T.List[T.Union[str, File]], kwargs: 'PreprocessKwArgs') -> ModuleReturnValue:
+ _sources = args[1:]
+ if _sources:
+ FeatureDeprecated.single_use('qt.preprocess positional sources', '0.59', state.subproject)
+ sources = _sources + kwargs['sources']
+ for s in sources:
+ if not isinstance(s, (str, File)):
+ raise build.InvalidArguments('Variadic arguments to qt.preprocess must be Strings or Files')
+ method = kwargs['method']
+
+ if kwargs['qresources']:
# custom output name set? -> one output file, multiple otherwise
+ rcc_kwargs: 'ResourceCompilerKwArgs' = {'name': '', 'sources': kwargs['qresources'], 'extra_args': kwargs['rcc_extra_arguments'], 'method': method}
if args:
- qrc_deps = []
- for i in rcc_files:
- qrc_deps += self.parse_qrc_deps(state, i)
- name = args[0]
- rcc_kwargs = {'input': rcc_files,
- 'output': name + '.cpp',
- 'command': [self.rcc, '-name', name, '-o', '@OUTPUT@', rcc_extra_arguments, '@INPUT@'],
- 'depend_files': qrc_deps}
- res_target = build.CustomTarget(name, state.subdir, state.subproject, rcc_kwargs)
- sources.append(res_target)
- else:
- for rcc_file in rcc_files:
- qrc_deps = self.parse_qrc_deps(state, rcc_file)
- if type(rcc_file) is str:
- basename = os.path.basename(rcc_file)
- elif type(rcc_file) is File:
- basename = os.path.basename(rcc_file.fname)
- name = 'qt' + str(self.qt_version) + '-' + basename.replace('.', '_')
- rcc_kwargs = {'input': rcc_file,
- 'output': name + '.cpp',
- 'command': [self.rcc, '-name', '@BASENAME@', '-o', '@OUTPUT@', rcc_extra_arguments, '@INPUT@'],
- 'depend_files': qrc_deps}
- if self.rcc_supports_depfiles:
- rcc_kwargs['depfile'] = name + '.d'
- rcc_kwargs['command'] += ['--depfile', '@DEPFILE@']
- res_target = build.CustomTarget(name, state.subdir, state.subproject, rcc_kwargs)
- sources.append(res_target)
- if ui_files:
- if not self.uic.found():
- raise MesonException(err_msg.format('UIC', f'uic-qt{self.qt_version}', self.qt_version))
- arguments = uic_extra_arguments + ['-o', '@OUTPUT@', '@INPUT@']
- ui_kwargs = {'output': 'ui_@BASENAME@.h',
- 'arguments': arguments}
- ui_gen = build.Generator([self.uic], ui_kwargs)
- ui_output = ui_gen.process_files(f'Qt{self.qt_version} ui', ui_files, state)
- sources.append(ui_output)
- inc = state.get_include_args(include_dirs=include_directories)
- compile_args = []
- for dep in unholder(dependencies):
- if isinstance(dep, Dependency):
- for arg in dep.get_all_compile_args():
- if arg.startswith('-I') or arg.startswith('-D'):
- compile_args.append(arg)
- else:
- raise MesonException('Argument is of an unacceptable type {!r}.\nMust be '
- 'either an external dependency (returned by find_library() or '
- 'dependency()) or an internal dependency (returned by '
- 'declare_dependency()).'.format(type(dep).__name__))
- if moc_headers:
- arguments = moc_extra_arguments + inc + compile_args + ['@INPUT@', '-o', '@OUTPUT@']
- moc_kwargs = {'output': 'moc_@BASENAME@.cpp',
- 'arguments': arguments}
- moc_gen = build.Generator([self.moc], moc_kwargs)
- moc_output = moc_gen.process_files(f'Qt{self.qt_version} moc header', moc_headers, state)
- sources.append(moc_output)
- if moc_sources:
- arguments = moc_extra_arguments + inc + compile_args + ['@INPUT@', '-o', '@OUTPUT@']
- moc_kwargs = {'output': '@BASENAME@.moc',
- 'arguments': arguments}
- moc_gen = build.Generator([self.moc], moc_kwargs)
- moc_output = moc_gen.process_files(f'Qt{self.qt_version} moc source', moc_sources, state)
- sources.append(moc_output)
- return ModuleReturnValue(sources, sources)
+ if not isinstance(args[0], str):
+ raise build.InvalidArguments('First argument to qt.preprocess must be a string')
+ rcc_kwargs['name'] = args[0]
+ sources.extend(self.compile_resources(state, tuple(), rcc_kwargs).return_value)
+
+ if kwargs['ui_files']:
+ ui_kwargs: 'UICompilerKwArgs' = {'sources': kwargs['ui_files'], 'extra_args': kwargs['uic_extra_arguments'], 'method': method}
+ sources.extend(self.compile_ui(state, tuple(), ui_kwargs).return_value)
+
+ if kwargs['moc_headers'] or kwargs['moc_sources']:
+ moc_kwargs: 'MocCompilerKwArgs' = {
+ 'extra_args': kwargs['moc_extra_arguments'],
+ 'sources': kwargs['moc_sources'],
+ 'headers': kwargs['moc_headers'],
+ 'include_directories': kwargs['include_directories'],
+ 'dependencies': kwargs['dependencies'],
+ 'method': method,
+ }
+ sources.extend(self.compile_moc(state, tuple(), moc_kwargs).return_value)
+
+ return ModuleReturnValue(sources, [sources])
@FeatureNew('qt.compile_translations', '0.44.0')
- @FeatureNewKwargs('qt.compile_translations', '0.56.0', ['qresource'])
- @FeatureNewKwargs('qt.compile_translations', '0.56.0', ['rcc_extra_arguments'])
- @permittedKwargs({'ts_files', 'qresource', 'rcc_extra_arguments', 'install', 'install_dir', 'build_by_default', 'method'})
- def compile_translations(self, state, args, kwargs):
- ts_files, install_dir = [extract_as_list(kwargs, c, pop=True) for c in ['ts_files', 'install_dir']]
- qresource = kwargs.get('qresource')
+ @noPosargs
+ @typed_kwargs(
+ 'qt.compile_translations',
+ KwargInfo('build_by_default', bool, default=False),
+ KwargInfo('install', bool, default=False),
+ KwargInfo('install_dir', str),
+ KwargInfo('method', str, default='auto'),
+ KwargInfo('qresource', str, since='0.56.0'),
+ KwargInfo('rcc_extra_arguments', ContainerTypeInfo(list, str), listify=True, default=[], since='0.56.0'),
+ KwargInfo('ts_files', ContainerTypeInfo(list, (str, File)), listify=True, default=[]),
+ )
+ def compile_translations(self, state: 'ModuleState', args: T.Tuple, kwargs: 'CompileTranslationsKwArgs') -> ModuleReturnValue:
+ ts_files = kwargs['ts_files']
+ install_dir = kwargs['install_dir']
+ qresource = kwargs['qresource']
if qresource:
if ts_files:
raise MesonException('qt.compile_translations: Cannot specify both ts_files and qresource')
if os.path.dirname(qresource) != '':
raise MesonException('qt.compile_translations: qresource file name must not contain a subdirectory.')
- qresource = File.from_built_file(state.subdir, qresource)
- infile_abs = os.path.join(state.environment.source_dir, qresource.relative_name())
- outfile_abs = os.path.join(state.environment.build_dir, qresource.relative_name())
+ qresource_file = File.from_built_file(state.subdir, qresource)
+ infile_abs = os.path.join(state.environment.source_dir, qresource_file.relative_name())
+ outfile_abs = os.path.join(state.environment.build_dir, qresource_file.relative_name())
os.makedirs(os.path.dirname(outfile_abs), exist_ok=True)
shutil.copy2(infile_abs, outfile_abs)
self.interpreter.add_build_def_file(infile_abs)
- rcc_file, nodes = self.qrc_nodes(state, qresource)
+ _, nodes = self._qrc_nodes(state, qresource_file)
for c in nodes:
if c.endswith('.qm'):
- ts_files.append(c.rstrip('.qm')+'.ts')
+ ts_files.append(c.rstrip('.qm') + '.ts')
else:
raise MesonException(f'qt.compile_translations: qresource can only contain qm files, found {c}')
- results = self.preprocess(state, [], {'qresources': qresource, 'rcc_extra_arguments': kwargs.get('rcc_extra_arguments', [])})
- self._detect_tools(state, kwargs.get('method', 'auto'))
- translations = []
+ results = self.preprocess(state, [], {'qresources': qresource, 'rcc_extra_arguments': kwargs['rcc_extra_arguments']})
+ self._detect_tools(state, kwargs['method'])
+ translations: T.List[build.CustomTarget] = []
for ts in ts_files:
if not self.lrelease.found():
raise MesonException('qt.compile_translations: ' +
@@ -320,4 +506,4 @@ class QtBaseModule(ExtensionModule):
if qresource:
return ModuleReturnValue(results.return_value[0], [results.new_objects, translations])
else:
- return ModuleReturnValue(translations, translations)
+ return ModuleReturnValue(translations, [translations])