summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Qt6-module.md3
-rw-r--r--docs/markdown/snippets/qt_has_tools_ignore.md12
-rw-r--r--mesonbuild/modules/_qt.py27
-rw-r--r--test cases/frameworks/4 qt/meson.build38
-rw-r--r--test cases/frameworks/4 qt/meson_options.txt1
-rw-r--r--unittests/linuxliketests.py14
6 files changed, 74 insertions, 21 deletions
diff --git a/docs/markdown/Qt6-module.md b/docs/markdown/Qt6-module.md
index 673b49996..7b6f94715 100644
--- a/docs/markdown/Qt6-module.md
+++ b/docs/markdown/Qt6-module.md
@@ -156,6 +156,9 @@ This method takes the following keyword arguments:
`true` or an enabled [`feature`](Build-options.md#features) and some tools are
missing Meson will abort.
- `method` string: The method to use to detect Qt, see [[dependency]]
+- `tools`: string[]: *Since 1.6.0*. List of tools to check. Testable tools
+ are `moc`, `uic`, `rcc` and `lrelease`. By default `tools` is set to `['moc',
+ 'uic', 'rcc', 'lrelease']`
## Dependencies
diff --git a/docs/markdown/snippets/qt_has_tools_ignore.md b/docs/markdown/snippets/qt_has_tools_ignore.md
new file mode 100644
index 000000000..4def48db2
--- /dev/null
+++ b/docs/markdown/snippets/qt_has_tools_ignore.md
@@ -0,0 +1,12 @@
+## Tools can be selected when calling `has_tools()` on the Qt modules
+
+When checking for the presence of Qt tools, you can now explictly ask Meson
+which tools you need. This is particularly useful when you do not need
+`lrelease` because you are not shipping any translations. For example:
+
+```meson
+qt6_mod = import('qt6')
+qt6_mod.has_tools(required: true, tools: ['moc', 'uic', 'rcc'])
+```
+
+valid tools are `moc`, `uic`, `rcc` and `lrelease`.
diff --git a/mesonbuild/modules/_qt.py b/mesonbuild/modules/_qt.py
index ebb8a3994..9f10c5826 100644
--- a/mesonbuild/modules/_qt.py
+++ b/mesonbuild/modules/_qt.py
@@ -27,6 +27,7 @@ if T.TYPE_CHECKING:
from ..interpreter import kwargs
from ..mesonlib import FileOrString
from ..programs import ExternalProgram
+ from typing_extensions import Literal
QtDependencyType = T.Union[QtPkgConfigDependency, QmakeQtDependency]
@@ -80,6 +81,7 @@ if T.TYPE_CHECKING:
class HasToolKwArgs(kwargs.ExtractRequired):
method: str
+ tools: T.List[Literal['moc', 'uic', 'rcc', 'lrelease']]
class CompileTranslationsKwArgs(TypedDict):
@@ -91,10 +93,21 @@ if T.TYPE_CHECKING:
rcc_extra_arguments: T.List[str]
ts_files: T.List[T.Union[str, File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]]
+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]:
+ invalid = set(checklist).difference(choices)
+ if invalid:
+ return f"invalid selections {', '.join(sorted(invalid))}, valid elements are {', '.join(sorted(choices))}."
+ return None
+
+ return inner
+
class QtBaseModule(ExtensionModule):
_tools_detected = False
_rcc_supports_depfiles = False
_moc_supports_depfiles = False
+ _set_of_qt_tools = {'moc', 'uic', 'rcc', 'lrelease'}
def __init__(self, interpreter: 'Interpreter', qt_version: int = 5):
ExtensionModule.__init__(self, interpreter)
@@ -102,10 +115,7 @@ class QtBaseModule(ExtensionModule):
# It is important that this list does not change order as the order of
# the returned ExternalPrograms will change as well
self.tools: T.Dict[str, T.Union[ExternalProgram, build.Executable]] = {
- 'moc': NonExistingExternalProgram('moc'),
- 'uic': NonExistingExternalProgram('uic'),
- 'rcc': NonExistingExternalProgram('rcc'),
- 'lrelease': NonExistingExternalProgram('lrelease'),
+ tool: NonExistingExternalProgram(tool) for tool in self._set_of_qt_tools
}
self.methods.update({
'has_tools': self.has_tools,
@@ -258,6 +268,10 @@ class QtBaseModule(ExtensionModule):
'qt.has_tools',
KwargInfo('required', (bool, options.UserFeatureOption), default=False),
KwargInfo('method', str, default='auto'),
+ KwargInfo('tools', ContainerTypeInfo(list, str), listify=True,
+ default=['moc', 'uic', 'rcc', 'lrelease'],
+ validator=_list_in_set_validator(_set_of_qt_tools),
+ since='1.6.0'),
)
def has_tools(self, state: 'ModuleState', args: T.Tuple, kwargs: 'HasToolKwArgs') -> bool:
method = kwargs.get('method', 'auto')
@@ -269,8 +283,9 @@ class QtBaseModule(ExtensionModule):
mlog.log('qt.has_tools skipped: feature', mlog.bold(feature), 'disabled')
return False
self._detect_tools(state, method, required=False)
- for tool in self.tools.values():
- if not tool.found():
+ for tool in kwargs['tools']:
+ assert tool in self._set_of_qt_tools, f'tools must be in {self._set_of_qt_tools}'
+ if not self.tools[tool].found():
if required:
raise MesonException('Qt tools not found')
return False
diff --git a/test cases/frameworks/4 qt/meson.build b/test cases/frameworks/4 qt/meson.build
index 54cd7cb9b..58ec4d16f 100644
--- a/test cases/frameworks/4 qt/meson.build
+++ b/test cases/frameworks/4 qt/meson.build
@@ -48,7 +48,13 @@ foreach qt : ['qt4', 'qt5', 'qt6']
qtdep = dependency(qt, modules : qt_modules, main : true, private_headers: true, required : required, method : get_option('method'))
if qtdep.found()
qtmodule = import(qt)
- assert(qtmodule.has_tools(), 'You may be missing a devel package. (qttools5-dev-tools on Debian based systems)')
+ if get_option('expect_lrelease')
+ assert(qtmodule.has_tools(), 'You may be missing a devel package. (qttools5-dev-tools on Debian based systems)')
+ else
+ assert(not qtmodule.has_tools(), 'Unexpectedly found lrelease')
+ assert(not qtmodule.has_tools(tools: ['lrelease']), 'Unexpectedly found lrelease')
+ assert(qtmodule.has_tools(tools: ['moc', 'uic', 'rcc']), 'You may be missing a devel package. (qttools5-dev-tools on Debian based systems)')
+ endif
# Test that fetching a variable works and yields a non-empty value
assert(qtdep.get_variable('prefix', configtool: 'QT_INSTALL_PREFIX') != '')
@@ -91,23 +97,25 @@ foreach qt : ['qt4', 'qt5', 'qt6']
# qt4-rcc and qt5-rcc take different arguments, for example qt4: ['-compress', '3']; qt5: '--compress=3'
qtmodule.preprocess(qt + 'testrccarg', qresources : files(['stuff.qrc', 'stuff2.qrc']), rcc_extra_arguments : '--compress=3', method : get_option('method'))
- translations_cpp = qtmodule.compile_translations(qresource: qt+'_lang.qrc')
- # unity builds suck and definitely cannot handle two qrc embeds in one compilation unit
- unityproof_translations = static_library(qt+'unityproof_translations', translations_cpp, dependencies: qtdep)
+ if get_option('expect_lrelease')
+ translations_cpp = qtmodule.compile_translations(qresource: qt+'_lang.qrc')
+ # unity builds suck and definitely cannot handle two qrc embeds in one compilation unit
+ unityproof_translations = static_library(qt+'unityproof_translations', translations_cpp, dependencies: qtdep)
- extra_cpp_args += '-DQT="@0@"'.format(qt)
- qexe = executable(qt + 'app',
- sources : ['main.cpp', 'mainWindow.cpp', # Sources that don't need preprocessing.
- prep, prep_rcc],
- dependencies : qtdep,
- link_with: unityproof_translations,
- cpp_args: extra_cpp_args,
- gui_app : true)
+ extra_cpp_args += '-DQT="@0@"'.format(qt)
+ qexe = executable(qt + 'app',
+ sources : ['main.cpp', 'mainWindow.cpp', # Sources that don't need preprocessing.
+ prep, prep_rcc],
+ dependencies : qtdep,
+ link_with: unityproof_translations,
+ cpp_args: extra_cpp_args,
+ gui_app : true)
- # We need a console test application because some test environments
- # do not have an X server.
+ # We need a console test application because some test environments
+ # do not have an X server.
- translations = qtmodule.compile_translations(ts_files : qt+'core_fr.ts', build_by_default : true)
+ translations = qtmodule.compile_translations(ts_files : qt+'core_fr.ts', build_by_default : true)
+ endif
qtcore = dependency(qt, modules : 'Core', method : get_option('method'))
diff --git a/test cases/frameworks/4 qt/meson_options.txt b/test cases/frameworks/4 qt/meson_options.txt
index 223f4fb0b..9a7513434 100644
--- a/test cases/frameworks/4 qt/meson_options.txt
+++ b/test cases/frameworks/4 qt/meson_options.txt
@@ -1,2 +1,3 @@
option('method', type : 'string', value : 'auto', description : 'The method to use to find Qt')
option('required', type : 'string', value : 'qt5', description : 'The version of Qt which is required to be present')
+option('expect_lrelease', type: 'boolean', value: true)
diff --git a/unittests/linuxliketests.py b/unittests/linuxliketests.py
index f92c992cc..bf0437bca 100644
--- a/unittests/linuxliketests.py
+++ b/unittests/linuxliketests.py
@@ -36,6 +36,7 @@ from mesonbuild.compilers.cpp import AppleClangCPPCompiler
from mesonbuild.compilers.objc import AppleClangObjCCompiler
from mesonbuild.compilers.objcpp import AppleClangObjCPPCompiler
from mesonbuild.dependencies.pkgconfig import PkgConfigDependency, PkgConfigCLI, PkgConfigInterface
+from mesonbuild.programs import NonExistingExternalProgram
import mesonbuild.modules.pkgconfig
PKG_CONFIG = os.environ.get('PKG_CONFIG', 'pkg-config')
@@ -317,6 +318,19 @@ class LinuxlikeTests(BasePlatformTests):
self.init(testdir, extra_args=['-Db_sanitize=address', '-Db_lundef=false'])
self.build()
+ def test_qt5dependency_no_lrelease(self):
+ '''
+ Test that qt5 detection with qmake works. This can't be an ordinary
+ test case because it involves setting the environment.
+ '''
+ testdir = os.path.join(self.framework_test_dir, '4 qt')
+ def _no_lrelease(self, prog, *args, **kwargs):
+ if 'lrelease' in prog:
+ return NonExistingExternalProgram(prog)
+ return self._interpreter.find_program_impl(prog, *args, **kwargs)
+ with mock.patch.object(mesonbuild.modules.ModuleState, 'find_program', _no_lrelease):
+ self.init(testdir, inprocess=True, extra_args=['-Dmethod=qmake', '-Dexpect_lrelease=false'])
+
def test_qt5dependency_qmake_detection(self):
'''
Test that qt5 detection with qmake works. This can't be an ordinary