Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow skipping the detection of specific tools in qt.has_tools() #13524

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/markdown/snippets/qt_has_tools_ignore.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## Tools can be skipped when calling `has_tools()` on the Qt modules

When checking for the presence of Qt tools, you can now ask Meson to not check
for the presence of a list of tools. 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, skip: ['lrelease'])
```
8 changes: 6 additions & 2 deletions mesonbuild/modules/_qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class PreprocessKwArgs(TypedDict):
class HasToolKwArgs(kwargs.ExtractRequired):

method: str
skip: T.List[str]

class CompileTranslationsKwArgs(TypedDict):

Expand Down Expand Up @@ -258,19 +259,22 @@ def _parse_qrc_deps(self, state: 'ModuleState',
'qt.has_tools',
KwargInfo('required', (bool, options.UserFeatureOption), default=False),
KwargInfo('method', str, default='auto'),
KwargInfo('skip', ContainerTypeInfo(list, str), listify=True, default=[]),
)
def has_tools(self, state: 'ModuleState', args: T.Tuple, kwargs: 'HasToolKwArgs') -> bool:
method = kwargs.get('method', 'auto')
skip = kwargs.get('skip')
# 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:
assert feature is not None, "for mypy"
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 name, tool in self.tools.items():
if name not in skip and not tool.found():
if required:
raise MesonException('Qt tools not found')
return False
Expand Down
2 changes: 1 addition & 1 deletion mesonbuild/programs.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def _search_dir(self, name: str, search_dir: T.Optional[str]) -> T.Optional[list
return [trial_ext]
return None

def _search_windows_special_cases(self, name: str, command: str) -> T.List[T.Optional[str]]:
def _search_windows_special_cases(self, name: str, command: T.Optional[str]) -> T.List[T.Optional[str]]:
'''
Lots of weird Windows quirks:
1. PATH search for @name returns files with extensions from PATHEXT,
Expand Down
37 changes: 22 additions & 15 deletions test cases/frameworks/4 qt/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ 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(qtmodule.has_tools(skip: ['lrelease']))
endif

# Test that fetching a variable works and yields a non-empty value
assert(qtdep.get_variable('prefix', configtool: 'QT_INSTALL_PREFIX') != '')
Expand Down Expand Up @@ -91,23 +96,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'))

Expand Down
1 change: 1 addition & 0 deletions test cases/frameworks/4 qt/meson_options.txt
Original file line number Diff line number Diff line change
@@ -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)
13 changes: 13 additions & 0 deletions unittests/linuxliketests.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,19 @@ def test_generate_gir_with_address_sanitizer(self):
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:
prog = 'lrelease-not-found'
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
Expand Down
Loading