build: replace kwargs in CustomTarget initializer

Because we don't want to pass the Interpreter kwargs into the build
layer. This turned out to be a mega commit, as there's really on elegant
way to make this change in an incremental way. On the nice side, mypy
made this change super easy, as nearly all of the calls to
`CustomTarget` are fully type checked!

It also turns out that we're not handling install_tags in custom_target
correctly, since we're not converting the boolean values into Optional
values!
pull/9900/head
Dylan Baker 3 years ago committed by Eli Schwartz
parent b402817fb6
commit 11f9638035
  1. 214
      mesonbuild/build.py
  2. 125
      mesonbuild/interpreter/interpreter.py
  3. 6
      mesonbuild/interpreter/kwargs.py
  4. 3
      mesonbuild/interpreter/type_checking.py
  5. 383
      mesonbuild/modules/gnome.py
  6. 7
      mesonbuild/modules/hotdoc.py
  7. 77
      mesonbuild/modules/i18n.py
  8. 18
      mesonbuild/modules/java.py
  9. 59
      mesonbuild/modules/qt.py
  10. 19
      mesonbuild/modules/unstable_external_project.py
  11. 22
      mesonbuild/modules/unstable_rust.py
  12. 27
      mesonbuild/modules/windows.py
  13. 2
      test cases/failing/41 custom target plainname many inputs/test.json

@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
from collections import OrderedDict
from dataclasses import dataclass, field
from functools import lru_cache
@ -24,6 +25,7 @@ import re
import textwrap
import typing as T
from . import environment
from . import dependencies
from . import mlog
@ -2328,47 +2330,78 @@ class CommandBase:
return final_cmd
class CustomTarget(Target, CommandBase):
known_kwargs = {
'input',
'output',
'command',
'capture',
'feed',
'install',
'install_dir',
'install_mode',
'install_tag',
'build_always',
'build_always_stale',
'depends',
'depend_files',
'depfile',
'build_by_default',
'override_options',
'console',
'env',
}
install_dir: T.List[T.Union[str, bool]]
typename = 'custom'
def __init__(self, name: str, subdir: str, subproject: str, kwargs: T.Mapping[str, T.Any],
absolute_paths: bool = False, backend: T.Optional['Backend'] = None):
self.typename = 'custom'
def __init__(self,
name: T.Optional[str],
subdir: str,
subproject: str,
command: T.Sequence[T.Union[
str, BuildTarget, CustomTarget, CustomTargetIndex, GeneratedList, programs.ExternalProgram, File]],
sources: T.Sequence[T.Union[
str, File, BuildTarget, CustomTarget, CustomTargetIndex,
ExtractedObjects, GeneratedList, programs.ExternalProgram]],
outputs: T.List[str],
*,
build_always_stale: bool = False,
build_by_default: T.Optional[bool] = None,
capture: bool = False,
console: bool = False,
depend_files: T.Optional[T.Sequence[FileOrString]] = None,
extra_depends: T.Optional[T.Sequence[T.Union[str, SourceOutputs]]] = None,
depfile: T.Optional[str] = None,
env: T.Optional[EnvironmentVariables] = None,
feed: bool = False,
install: bool = False,
install_dir: T.Optional[T.Sequence[T.Union[str, bool]]] = None,
install_mode: T.Optional[FileMode] = None,
install_tag: T.Optional[T.Sequence[T.Optional[str]]] = None,
override_options: T.Optional[T.Dict[OptionKey, str]] = None,
absolute_paths: bool = False,
backend: T.Optional['Backend'] = None,
):
# TODO expose keyword arg to make MachineChoice.HOST configurable
super().__init__(name, subdir, subproject, False, MachineChoice.HOST)
self.sources = list(sources)
self.outputs = substitute_values(
outputs, get_filenames_templates_dict(
get_sources_string_names(sources, backend),
[]))
self.build_by_default = build_by_default if build_by_default is not None else install
self.build_always_stale = build_always_stale
self.capture = capture
self.console = console
self.depend_files = list(depend_files or [])
self.dependencies: T.List[T.Union[CustomTarget, BuildTarget]] = []
self.extra_depends: T.List[T.Union[CustomTarget, BuildTarget]] = []
self.depend_files = [] # Files that this target depends on but are not on the command line.
self.depfile = None
self.process_kwargs(kwargs, backend)
# must be after depend_files and dependencies
self.command = self.flatten_command(command)
self.depfile = depfile
self.env = env or EnvironmentVariables()
self.extra_depends = list(extra_depends or [])
self.feed = feed
self.install = install
self.install_dir = list(install_dir or [])
self.install_mode = install_mode
_install_tag: T.List[T.Optional[str]]
if not install_tag:
_install_tag = [None] * len(self.outputs)
elif len(install_tag) == 1:
_install_tag = list(install_tag) * len(self.outputs)
else:
_install_tag = list(install_tag)
self.install_tag = _install_tag
self.name = name if name else self.outputs[0]
if override_options:
for k, v in override_options.items():
if k.lang:
self.option_overrides_compiler[k.evolve(machine=self.for_machine)] = v
else:
self.option_overrides_base[k] = v
# Whether to use absolute paths for all files on the commandline
self.absolute_paths = absolute_paths
unknowns = []
for k in kwargs:
if k not in CustomTarget.known_kwargs:
unknowns.append(k)
if unknowns:
mlog.warning('Unknown keyword arguments in target {}: {}'.format(self.name, ', '.join(unknowns)))
def get_default_install_dir(self, environment) -> T.Tuple[str, str]:
return None, None
@ -2405,119 +2438,6 @@ class CustomTarget(Target, CommandBase):
bdeps.update(d.get_transitive_build_target_deps())
return bdeps
def process_kwargs(self, kwargs, backend):
self.process_kwargs_base(kwargs)
self.sources = extract_as_list(kwargs, 'input')
if 'output' not in kwargs:
raise InvalidArguments('Missing keyword argument "output".')
self.outputs = listify(kwargs['output'])
# This will substitute values from the input into output and return it.
inputs = get_sources_string_names(self.sources, backend)
values = get_filenames_templates_dict(inputs, [])
for i in self.outputs:
if not isinstance(i, str):
raise InvalidArguments('Output argument not a string.')
if i == '':
raise InvalidArguments('Output must not be empty.')
if i.strip() == '':
raise InvalidArguments('Output must not consist only of whitespace.')
if has_path_sep(i):
raise InvalidArguments(f'Output {i!r} must not contain a path segment.')
if '@INPUT@' in i or '@INPUT0@' in i:
m = 'Output cannot contain @INPUT@ or @INPUT0@, did you ' \
'mean @PLAINNAME@ or @BASENAME@?'
raise InvalidArguments(m)
# We already check this during substitution, but the error message
# will be unclear/confusing, so check it here.
if len(inputs) != 1 and ('@PLAINNAME@' in i or '@BASENAME@' in i):
m = "Output cannot contain @PLAINNAME@ or @BASENAME@ when " \
"there is more than one input (we can't know which to use)"
raise InvalidArguments(m)
self.outputs = substitute_values(self.outputs, values)
if not self.name:
self.name = self.outputs[0]
self.capture = kwargs.get('capture', False)
if self.capture and len(self.outputs) != 1:
raise InvalidArguments('Capturing can only output to a single file.')
self.feed = kwargs.get('feed', False)
if self.feed and len(self.sources) != 1:
raise InvalidArguments('Feeding can only input from a single file.')
self.console = kwargs.get('console', False)
if not isinstance(self.console, bool):
raise InvalidArguments('"console" kwarg only accepts booleans')
if self.capture and self.console:
raise InvalidArguments("Can't both capture output and output to console")
if 'command' not in kwargs:
raise InvalidArguments('Missing keyword argument "command".')
if kwargs.get('depfile') is not None:
depfile = kwargs['depfile']
if not isinstance(depfile, str):
raise InvalidArguments('Depfile must be a string.')
if os.path.basename(depfile) != depfile:
raise InvalidArguments('Depfile must be a plain filename without a subdirectory.')
self.depfile = depfile
self.command = self.flatten_command(kwargs['command'])
for c in self.command:
if self.capture and isinstance(c, str) and '@OUTPUT@' in c:
raise InvalidArguments('@OUTPUT@ is not allowed when capturing output.')
if self.feed and isinstance(c, str) and '@INPUT@' in c:
raise InvalidArguments('@INPUT@ is not allowed when feeding input.')
if 'install' in kwargs:
self.install = kwargs['install']
if not isinstance(self.install, bool):
raise InvalidArguments('"install" must be boolean.')
if self.install:
if not kwargs.get('install_dir', False):
raise InvalidArguments('"install_dir" must be specified '
'when installing a target')
if isinstance(kwargs['install_dir'], list):
FeatureNew.single_use('multiple install_dir for custom_target', '0.40.0', self.subproject)
# If an item in this list is False, the output corresponding to
# the list index of that item will not be installed
self.install_dir = typeslistify(kwargs['install_dir'], (str, bool))
self.install_mode = kwargs.get('install_mode', None)
# If only one tag is provided, assume all outputs have the same tag.
# Otherwise, we must have as much tags as outputs.
install_tag: T.List[T.Union[str, bool, None]] = typeslistify(kwargs.get('install_tag', []), (str, bool, type(None)))
if not install_tag:
self.install_tag = [None] * len(self.outputs)
elif len(install_tag) == 1:
self.install_tag = install_tag * len(self.outputs)
elif install_tag and len(install_tag) != len(self.outputs):
m = f'Target {self.name!r} has {len(self.outputs)} outputs but {len(install_tag)} "install_tag"s were found.'
raise InvalidArguments(m)
else:
self.install_tag = install_tag
else:
self.install = False
self.install_dir = []
self.install_mode = None
self.install_tag = []
if kwargs.get('build_always') is not None and kwargs.get('build_always_stale') is not None:
raise InvalidArguments('build_always and build_always_stale are mutually exclusive. Combine build_by_default and build_always_stale.')
elif kwargs.get('build_always') is not None:
if kwargs.get('build_by_default') is not None:
self.build_by_default = kwargs['build_always']
self.build_always_stale = kwargs['build_always']
elif kwargs.get('build_always_stale') is not None:
self.build_always_stale = kwargs['build_always_stale']
if not isinstance(self.build_always_stale, bool):
raise InvalidArguments('Argument build_always_stale must be a boolean.')
extra_deps, depend_files = (extract_as_list(kwargs, c, pop=False) for c in ['depends', 'depend_files'])
for ed in extra_deps:
if not isinstance(ed, (CustomTarget, BuildTarget)):
raise InvalidArguments('Can only depend on toplevel targets: custom_target or build_target '
f'(executable or a library) got: {type(ed)}({ed})')
self.extra_depends.append(ed)
for i in depend_files:
if isinstance(i, (File, str)):
self.depend_files.append(i)
else:
mlog.debug(i)
raise InvalidArguments(f'Unknown type {type(i).__name__!r} in depend_files.')
self.env = kwargs.get('env')
def get_dependencies(self):
return self.dependencies

@ -50,7 +50,9 @@ from .interpreterobjects import (
NullSubprojectInterpreter,
)
from .type_checking import (
COMMAND_KW, CT_BUILD_ALWAYS, CT_BUILD_ALWAYS_STALE,
COMMAND_KW,
CT_BUILD_ALWAYS,
CT_BUILD_ALWAYS_STALE,
CT_BUILD_BY_DEFAULT,
CT_INPUT_KW,
CT_INSTALL_DIR_KW,
@ -1696,8 +1698,14 @@ external dependencies (including libraries) must go to "dependencies".''')
else:
vcs_cmd = [' '] # executing this cmd will fail in vcstagger.py and force to use the fallback string
# vcstagger.py parameters: infile, outfile, fallback, source_dir, replace_string, regex_selector, command...
cmd_kwargs = {
'command': self.environment.get_build_command() + \
self._validate_custom_target_outputs(len(kwargs['input']) > 1, kwargs['output'], "vcs_tag")
tg = build.CustomTarget(
kwargs['output'][0],
self.subdir,
self.subproject,
self.environment.get_build_command() + \
['--internal',
'vcstagger',
'@INPUT0@',
@ -1706,12 +1714,13 @@ external dependencies (including libraries) must go to "dependencies".''')
source_dir,
replace_string,
regex_selector] + vcs_cmd,
'input': kwargs['input'],
'output': kwargs['output'],
'build_by_default': True,
'build_always_stale':True,
}
return self._func_custom_target_impl(node, [kwargs['output']], cmd_kwargs)
self.source_strings_to_files(kwargs['input']),
kwargs['output'],
build_by_default=True,
build_always_stale=True,
)
self.add_target(tg.name, tg)
return tg
@FeatureNew('subdir_done', '0.46.0')
@noPosargs
@ -1719,6 +1728,18 @@ external dependencies (including libraries) must go to "dependencies".''')
def func_subdir_done(self, node, args, kwargs):
raise SubdirDoneRequest()
@staticmethod
def _validate_custom_target_outputs(has_multi_in: bool, outputs: T.Iterable[str], name: str) -> None:
"""Checks for additional invalid values in a custom_target output.
This cannot be done with typed_kwargs because it requires the number of
inputs.
"""
for out in outputs:
if has_multi_in and ('@PLAINNAME@' in out or '@BASENAME@' in out):
raise InvalidArguments(f'{name}: output cannot containe "@PLAINNAME@" or "@BASENAME@" '
'when there is more than one input (we can\'t know which to use)')
@typed_pos_args('custom_target', optargs=[str])
@typed_kwargs(
'custom_target',
@ -1747,49 +1768,87 @@ external dependencies (including libraries) must go to "dependencies".''')
FeatureNew.single_use('substitutions in custom_target depfile', '0.47.0', self.subproject, location=node)
# Don't mutate the kwargs
kwargs = kwargs.copy()
build_by_default = kwargs['build_by_default']
build_always_stale = kwargs['build_always_stale']
# Remap build_always to build_by_default and build_always_stale
if kwargs['build_always'] is not None and kwargs['build_always_stale'] is not None:
raise InterpreterException('CustomTarget: "build_always" and "build_always_stale" are mutually exclusive')
if kwargs['build_by_default'] is None and kwargs['install']:
kwargs['build_by_default'] = True
if build_by_default is None and kwargs['install']:
build_by_default = True
elif kwargs['build_always'] is not None:
if kwargs['build_by_default'] is None:
kwargs['build_by_default'] = kwargs['build_always']
kwargs['build_always_stale'] = kwargs['build_by_default']
# Set this to None to satisfy process_kwargs
kwargs['build_always'] = None
if build_by_default is None:
build_by_default = kwargs['build_always']
build_always_stale = kwargs['build_by_default']
# These are are nullaable so that we can know whether they're explicitly
# set or not. If they haven't been overwritten, set them to their true
# default
if kwargs['build_by_default'] is None:
kwargs['build_by_default'] = False
if kwargs['build_always_stale'] is None:
kwargs['build_always_stale'] = False
if build_by_default is None:
build_by_default = False
if build_always_stale is None:
build_always_stale = False
return self._func_custom_target_impl(node, args, kwargs)
def _func_custom_target_impl(self, node, args, kwargs):
'Implementation-only, without FeatureNew checks, for internal use'
name = args[0]
if name is None:
# name will default to first output, but we cannot do that yet because
# they could need substitutions (e.g. @BASENAME@) first. CustomTarget()
# will take care of setting a proper default but name must be an empty
# string in the meantime.
FeatureNew('custom_target() with no name argument', '0.60.0', location=node).use(self.subproject)
FeatureNew.single_use('custom_target() with no name argument', '0.60.0', self.subproject, location=node)
name = ''
if 'input' in kwargs:
kwargs['input'] = self.source_strings_to_files(extract_as_list(kwargs, 'input'), strict=False)
if 'command' in kwargs and isinstance(kwargs['command'], list) and kwargs['command']:
if isinstance(kwargs['command'][0], str):
kwargs['command'][0] = self.find_program_impl([kwargs['command'][0]])
tg = build.CustomTarget(name, self.subdir, self.subproject, kwargs, backend=self.backend)
inputs = self.source_strings_to_files(kwargs['input'], strict=False)
command = kwargs['command']
if command and isinstance(command[0], str):
command[0] = self.find_program_impl([command[0]])
if len(inputs) > 1 and kwargs['feed']:
raise InvalidArguments('custom_target: "feed" keyword argument can only be used used with a single input')
if len(kwargs['output']) > 1 and kwargs['capture']:
raise InvalidArguments('custom_target: "capture" keyword argument can only be used used with a single output')
if kwargs['capture'] and kwargs['console']:
raise InvalidArguments('custom_target: "capture" and "console" keyword arguments are mutually exclusive')
for c in command:
if kwargs['capture'] and isinstance(c, str) and '@OUTPUT@' in c:
raise InvalidArguments('custom_target: "capture" keyword argument cannot be used with "@OUTPUT@"')
if kwargs['feed'] and isinstance(c, str) and '@INPUT@' in c:
raise InvalidArguments('custom_target: "feed" keyword argument cannot be used with "@INPUT@"')
if kwargs['install'] and not kwargs['install_dir']:
raise InvalidArguments('custom_target: "install_dir" keyword argument must be set when "install" is true.')
if len(kwargs['install_dir']) > 1:
FeatureNew.single_use('multiple install_dir for custom_target', '0.40.0', self.subproject, location=node)
if len(kwargs['install_tag']) not in {0, 1, len(kwargs['output'])}:
raise InvalidArguments('custom_target: install_tag argument must have 0 or 1 outputs, '
'or the same number of elements as the output keyword argument. '
f'(there are {len(kwargs["install_tag"])} install_tags, '
f'and {len(kwargs["output"])} outputs)')
self._validate_custom_target_outputs(len(inputs) > 1, kwargs['output'], "custom_target")
tg = build.CustomTarget(
name,
self.subdir,
self.subproject,
command,
inputs,
kwargs['output'],
build_always_stale=build_always_stale,
build_by_default=build_by_default,
capture=kwargs['capture'],
console=kwargs['console'],
depend_files=kwargs['depend_files'],
depfile=kwargs['depfile'],
extra_depends=kwargs['depends'],
env=kwargs['env'],
feed=kwargs['feed'],
install=kwargs['install'],
install_dir=kwargs['install_dir'],
install_mode=kwargs['install_mode'],
install_tag=kwargs['install_tag'],
override_options=kwargs['override_options'],
backend=self.backend)
self.add_target(tg.name, tg)
return tg

@ -167,8 +167,8 @@ class RunTarget(TypedDict):
class CustomTarget(TypedDict):
build_always: bool
build_always_stale: bool
build_by_default: bool
build_always_stale: T.Optional[bool]
build_by_default: T.Optional[bool]
capture: bool
command: T.List[T.Union[str, build.BuildTarget, build.CustomTarget,
build.CustomTargetIndex, ExternalProgram, File]]
@ -183,7 +183,7 @@ class CustomTarget(TypedDict):
install: bool
install_dir: T.List[T.Union[str, bool]]
install_mode: FileMode
install_tag: T.List[T.Union[str, bool]]
install_tag: T.List[T.Optional[str]]
output: T.List[str]
override_options: T.Dict[OptionKey, str]

@ -244,6 +244,8 @@ def _output_validator(outputs: T.List[str]) -> T.Optional[str]:
return 'Output must not consist only of whitespace.'
elif has_path_sep(i):
return f'Output {i!r} must not contain a path segment.'
elif '@INPUT' in i:
return f'output {i!r} contains "@INPUT", which is invalid. Did you mean "@PLAINNAME@" or "@BASENAME@?'
return None
@ -269,6 +271,7 @@ CT_INSTALL_TAG_KW: KwargInfo[T.List[T.Union[str, bool]]] = KwargInfo(
listify=True,
default=[],
since='0.60.0',
convertor=lambda x: [y if isinstance(y, str) else None for y in x],
)
INSTALL_KW = KwargInfo('install', bool, default=False)

@ -148,7 +148,7 @@ if T.TYPE_CHECKING:
build_by_default: T.Optional[bool]
depend_files: T.List[mesonlib.File]
extra_args: T.List[str]
install_dir: T.List[T.Union[str, bool]]
install_dir: T.Union[str, bool]
install_header: bool
internal: bool
nostdinc: bool
@ -404,7 +404,7 @@ class GnomeModule(ExtensionModule):
glib_version = self._get_native_glib_version(state)
glib_compile_resources = state.find_program('glib-compile-resources')
cmd = [glib_compile_resources, '@INPUT@']
cmd: T.List[T.Union[ExternalProgram, str]] = [glib_compile_resources, '@INPUT@']
source_dirs = kwargs['source_dir']
dependencies = kwargs['dependencies']
@ -486,39 +486,47 @@ class GnomeModule(ExtensionModule):
if install_header and not kwargs['export']:
raise MesonException('GResource header is installed yet export is not enabled')
c_kwargs: T.Dict[str, T.Any] = {
'build_by_default': kwargs['build_by_default'],
'depends': depends,
'input': input_file,
'install': kwargs['install'],
'install_dir': kwargs['install_dir'] or [],
'output': output,
}
depfile: T.Optional[str] = None
target_cmd: T.List[T.Union[ExternalProgram, str]]
if not mesonlib.version_compare(glib_version, gresource_dep_needed_version):
# This will eventually go out of sync if dependencies are added
c_kwargs['depend_files'] = depend_files
c_kwargs['command'] = cmd
target_cmd = cmd
else:
depfile = f'{output}.d'
c_kwargs['depfile'] = depfile
c_kwargs['command'] = copy.copy(cmd) + ['--dependency-file', '@DEPFILE@']
target_c = GResourceTarget(name, state.subdir, state.subproject, c_kwargs)
depend_files = []
target_cmd = copy.copy(cmd) + ['--dependency-file', '@DEPFILE@']
target_c = GResourceTarget(
name,
state.subdir,
state.subproject,
target_cmd,
[input_file],
[output],
build_by_default=kwargs['build_by_default'],
depfile=depfile,
depend_files=depend_files,
extra_depends=depends,
install=kwargs['install'],
install_dir=[kwargs['install_dir']] if kwargs['install_dir'] else [],
)
if gresource: # Only one target for .gresource files
return ModuleReturnValue(target_c, [target_c])
h_kwargs: T.Dict[str, T.Any] = {
'command': cmd,
'input': input_file,
'output': f'{target_name}.h',
# The header doesn't actually care about the files yet it errors if missing
'depends': depends,
'build_by_default': kwargs['build_by_default'],
'install_dir': kwargs['install_dir'] or [state.environment.coredata.get_option(mesonlib.OptionKey('includedir'))],
}
if install_header:
h_kwargs['install'] = install_header
target_h = GResourceHeaderTarget(f'{target_name}_h', state.subdir, state.subproject, h_kwargs)
install_dir = kwargs['install_dir'] or state.environment.coredata.get_option(mesonlib.OptionKey('includedir'))
assert isinstance(install_dir, str), 'for mypy'
target_h = GResourceHeaderTarget(
f'{target_name}_h',
state.subdir,
state.subproject,
cmd,
[input_file],
[f'{target_name}.h'],
build_by_default=kwargs['build_by_default'],
extra_depends=depends,
install=install_header,
install_dir=[install_dir],
)
rv = [target_c, target_h]
return ModuleReturnValue(rv, rv)
@ -932,18 +940,19 @@ class GnomeModule(ExtensionModule):
elif install_dir is False:
install = False
scankwargs = {
'input': generated_files,
'output': girfile,
'command': scan_command,
'depends': depends,
'install': install,
'install_dir': install_dir,
'install_tag': 'devel',
'build_by_default': kwargs['build_by_default'],
}
return GirTarget(girfile, state.subdir, state.subproject, scankwargs)
return GirTarget(
girfile,
state.subdir,
state.subproject,
scan_command,
generated_files,
[girfile],
build_by_default=kwargs['build_by_default'],
extra_depends=depends,
install=install,
install_dir=[install_dir],
install_tag=['devel'],
)
@staticmethod
def _make_typelib_target(state: 'ModuleState', typelib_output: str,
@ -960,17 +969,18 @@ class GnomeModule(ExtensionModule):
elif install_dir is False:
install = False
typelib_kwargs = {
'input': generated_files,
'output': [typelib_output],
'command': list(typelib_cmd),
'install': install,
'install_dir': install_dir,
'install_tag': 'typelib',
'build_by_default': kwargs['build_by_default'],
}
return TypelibTarget(typelib_output, state.subdir, state.subproject, typelib_kwargs)
return TypelibTarget(
typelib_output,
state.subdir,
state.subproject,
typelib_cmd,
generated_files,
[typelib_output],
install=install,
install_dir=[install_dir],
install_tag=['typelib'],
build_by_default=kwargs['build_by_default'],
)
@staticmethod
def _gather_typelib_includes_and_update_depends(
@ -1178,16 +1188,21 @@ class GnomeModule(ExtensionModule):
srcdir = os.path.join(state.build_to_src, state.subdir)
outdir = state.subdir
cmd = [state.find_program('glib-compile-schemas'), '--targetdir', outdir, srcdir]
ct_kwargs = T.cast(T.Dict[str, T.Any], kwargs.copy())
ct_kwargs['command'] = cmd
ct_kwargs['input'] = []
ct_kwargs['output'] = 'gschemas.compiled'
cmd: T.List[T.Union[ExternalProgram, str]] = [state.find_program('glib-compile-schemas'), '--targetdir', outdir, srcdir]
if state.subdir == '':
targetname = 'gsettings-compile'
else:
targetname = 'gsettings-compile-' + state.subdir.replace('/', '_')
target_g = build.CustomTarget(targetname, state.subdir, state.subproject, ct_kwargs)
target_g = build.CustomTarget(
targetname,
state.subdir,
state.subproject,
cmd,
[],
['gschemas.compiled'],
build_by_default=kwargs['build_by_default'],
depend_files=kwargs['depend_files'],
)
self._devenv_prepend('GSETTINGS_SCHEMA_DIR', os.path.join(state.environment.get_build_dir(), state.subdir))
return ModuleReturnValue(target_g, [target_g])
@ -1289,22 +1304,27 @@ class GnomeModule(ExtensionModule):
potargets.append(potarget)
gmo_file = project_id + '-' + l + '.gmo'
gmo_kwargs = {'command': [msgfmt, '@INPUT@', '-o', '@OUTPUT@'],
'input': po_file,
'output': gmo_file,
}
gmotarget = build.CustomTarget(f'help-{project_id}-{l}-gmo', l_subdir, state.subproject, gmo_kwargs)
gmotarget = build.CustomTarget(
f'help-{project_id}-{l}-gmo',
l_subdir,
state.subproject,
[msgfmt, '@INPUT@', '-o', '@OUTPUT@'],
[po_file],
[gmo_file],
)
targets.append(gmotarget)
merge_kwargs = {'command': [itstool, '-m', os.path.join(l_subdir, gmo_file),
'-o', '@OUTDIR@', '@INPUT@'],
'input': sources_files,
'output': sources,
'depends': gmotarget,
'install': True,
'install_dir': l_install_dir,
}
mergetarget = build.CustomTarget(f'help-{project_id}-{l}', l_subdir, state.subproject, merge_kwargs)
mergetarget = build.CustomTarget(
f'help-{project_id}-{l}',
l_subdir,
state.subproject,
[itstool, '-m', os.path.join(l_subdir, gmo_file), '-o', '@OUTDIR@', '@INPUT@'],
sources_files,
sources,
extra_depends=[gmotarget],
install=True,
install_dir=[l_install_dir],
)
targets.append(mergetarget)
allpotarget = build.AliasTarget(f'help-{project_id}-update-po', potargets,
@ -1377,15 +1397,16 @@ class GnomeModule(ExtensionModule):
else:
header_dirs.append(src_dir)
t_args = ['--internal', 'gtkdoc',
'--sourcedir=' + state.environment.get_source_dir(),
'--builddir=' + state.environment.get_build_dir(),
'--subdir=' + state.subdir,
'--headerdirs=' + '@@'.join(header_dirs),
'--mainfile=' + main_file,
'--modulename=' + modulename,
'--moduleversion=' + moduleversion,
'--mode=' + kwargs['mode']]
t_args: T.List[str] = [
'--internal', 'gtkdoc',
'--sourcedir=' + state.environment.get_source_dir(),
'--builddir=' + state.environment.get_build_dir(),
'--subdir=' + state.subdir,
'--headerdirs=' + '@@'.join(header_dirs),
'--mainfile=' + main_file,
'--modulename=' + modulename,
'--moduleversion=' + moduleversion,
'--mode=' + kwargs['mode']]
for tool in ['scan', 'scangobj', 'mkdb', 'mkhtml', 'fixxref']:
program_name = 'gtkdoc-' + tool
program = state.find_program(program_name)
@ -1432,12 +1453,16 @@ class GnomeModule(ExtensionModule):
t_args.append(f'--installdir={"@@".join(kwargs["install_dir"])}')
t_args += self._get_build_args(kwargs['c_args'], kwargs['include_directories'],
kwargs['dependencies'], state, depends)
custom_kwargs = {'output': modulename + '-decl.txt',
'command': command + t_args,
'depends': depends,
'build_always_stale': True,
}
custom_target = build.CustomTarget(targetname, state.subdir, state.subproject, custom_kwargs)
custom_target = build.CustomTarget(
targetname,
state.subdir,
state.subproject,
command + t_args,
[],
[f'{modulename}-decl.txt'],
build_always_stale=True,
extra_depends=depends,
)
alias_target = build.AliasTarget(targetname, [custom_target], state.subdir, state.subproject)
if kwargs['check']:
check_cmd = state.find_program('gtkdoc-check')
@ -1555,11 +1580,7 @@ class GnomeModule(ExtensionModule):
# Added in https://gitlab.gnome.org/GNOME/glib/commit/e4d68c7b3e8b01ab1a4231bf6da21d045cb5a816 (2.55.2)
# Fixed in https://gitlab.gnome.org/GNOME/glib/commit/cd1f82d8fc741a2203582c12cc21b4dacf7e1872 (2.56.2)
if mesonlib.version_compare(glib_version, '>= 2.56.2'):
custom_kwargs = {'input': xml_files,
'output': output,
'command': cmd + ['--body', '--output', '@OUTPUT@', '@INPUT@'],
'build_by_default': build_by_default
}
c_cmd = cmd + ['--body', '--output', '@OUTPUT@', '@INPUT@']
else:
if kwargs['docbook'] is not None:
docbook = kwargs['docbook']
@ -1572,36 +1593,39 @@ class GnomeModule(ExtensionModule):
else:
self._print_gdbus_warning()
cmd += ['--generate-c-code', '@OUTDIR@/' + namebase, '@INPUT@']
custom_kwargs = {'input': xml_files,
'output': output,
'command': cmd,
'build_by_default': build_by_default
}
cfile_custom_target = build.CustomTarget(output, state.subdir, state.subproject, custom_kwargs)
c_cmd = cmd
cfile_custom_target = build.CustomTarget(
output,
state.subdir,
state.subproject,
c_cmd,
xml_files,
[output],
build_by_default=build_by_default,
)
targets.append(cfile_custom_target)
output = namebase + '.h'
if mesonlib.version_compare(glib_version, '>= 2.56.2'):
custom_kwargs = {'input': xml_files,
'output': output,
'command': cmd + ['--header', '--output', '@OUTPUT@', '@INPUT@'],
'build_by_default': build_by_default,
'install': install_header,
'install_dir': install_dir
}
hfile_cmd = cmd + ['--header', '--output', '@OUTPUT@', '@INPUT@']
depends = []
else:
custom_kwargs = {'input': xml_files,
'output': output,
'command': cmd,
'build_by_default': build_by_default,
'install': install_header,
'install_dir': install_dir,
'depends': cfile_custom_target
}
hfile_custom_target = build.CustomTarget(output, state.subdir, state.subproject, custom_kwargs)
hfile_cmd = cmd
depends = [cfile_custom_target]
hfile_custom_target = build.CustomTarget(
output,
state.subdir,
state.subproject,
hfile_cmd,
xml_files,
[output],
build_by_default=build_by_default,
extra_depends=depends,
install=install_header,
install_dir=[install_dir],
)
targets.append(hfile_custom_target)
if kwargs['docbook'] is not None:
@ -1609,8 +1633,6 @@ class GnomeModule(ExtensionModule):
if not isinstance(docbook, str):
raise MesonException('docbook value must be a string.')
docbook_cmd = cmd + ['--output-directory', '@OUTDIR@', '--generate-docbook', docbook, '@INPUT@']
# The docbook output is always ${docbook}-${name_of_xml_file}
output = namebase + '-docbook'
outputs = []
@ -1618,20 +1640,22 @@ class GnomeModule(ExtensionModule):
outputs.append('{}-{}'.format(docbook, os.path.basename(str(f))))
if mesonlib.version_compare(glib_version, '>= 2.56.2'):
custom_kwargs = {'input': xml_files,
'output': outputs,
'command': docbook_cmd,
'build_by_default': build_by_default
}
docbook_cmd = cmd + ['--output-directory', '@OUTDIR@', '--generate-docbook', docbook, '@INPUT@']
depends = []
else:
custom_kwargs = {'input': xml_files,
'output': outputs,
'command': cmd,
'build_by_default': build_by_default,
'depends': cfile_custom_target
}
docbook_custom_target = build.CustomTarget(output, state.subdir, state.subproject, custom_kwargs)
docbook_cmd = cmd
depends = [cfile_custom_target]
docbook_custom_target = build.CustomTarget(
output,
state.subdir,
state.subproject,
docbook_cmd,
xml_files,
outputs,
build_by_default=build_by_default,
extra_depends=depends,
)
targets.append(docbook_custom_target)
return ModuleReturnValue(targets, targets)
@ -1835,18 +1859,23 @@ class GnomeModule(ExtensionModule):
) -> build.CustomTarget:
real_cmd: T.List[T.Union[str, ExternalProgram]] = [state.find_program(['glib-mkenums', 'mkenums'])]
real_cmd.extend(cmd)
custom_kwargs = {
'input': sources,
'output': [output],
'capture': True,
'command': real_cmd,
'install': install,
'install_dir': install_dir or state.environment.coredata.get_option(mesonlib.OptionKey('includedir')),
'depends': list(depends or []),
}
return build.CustomTarget(output, state.subdir, state.subproject, custom_kwargs,
# https://github.com/mesonbuild/meson/issues/973
absolute_paths=True)
_install_dir = install_dir or state.environment.coredata.get_option(mesonlib.OptionKey('includedir'))
assert isinstance(_install_dir, str), 'for mypy'
return build.CustomTarget(
output,
state.subdir,
state.subproject,
real_cmd,
sources,
[output],
capture=True,
install=install,
install_dir=[_install_dir],
extra_depends=depends,
# https://github.com/mesonbuild/meson/issues/973
absolute_paths=True,
)
@typed_pos_args('gnome.genmarshal', str)
@typed_kwargs(
@ -1886,36 +1915,45 @@ class GnomeModule(ExtensionModule):
cmd.append(f'--{k.replace("_", "-")}')
install_header = kwargs['install_header']
install_dir: T.List[T.Union[str, bool]] = kwargs['install_dir'] or []
custom_kwargs: T.Dict[str, T.Any] = {
'input': sources,
'depend_files': kwargs['depend_files'],
'install_dir': kwargs['install_dir'],
}
capture = False
# https://github.com/GNOME/glib/commit/0fbc98097fac4d3e647684f344e508abae109fdf
if mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.51.0'):
cmd += ['--output', '@OUTPUT@']
else:
custom_kwargs['capture'] = True
capture = True
header_file = output + '.h'
custom_kwargs['command'] = cmd + ['--body', '@INPUT@']
c_cmd = cmd + ['--body', '@INPUT@']
if mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.53.4'):
# Silence any warnings about missing prototypes
custom_kwargs['command'] += ['--include-header', header_file]
custom_kwargs['output'] = output + '.c'
body = build.CustomTarget(output + '_c', state.subdir, state.subproject, custom_kwargs)
custom_kwargs['install'] = install_header
custom_kwargs['install_dir'] = install_dir
c_cmd += ['--include-header', header_file]
body = build.CustomTarget(
output + '_c',
state.subdir,
state.subproject,
c_cmd,
sources,
[f'{output}.c'],
capture=capture,
depend_files=kwargs['depend_files'],
)
h_cmd = cmd + ['--header', '@INPUT@']
if new_genmarshal:
cmd += ['--pragma-once']
custom_kwargs['command'] = cmd + ['--header', '@INPUT@']
custom_kwargs['output'] = header_file
header = build.CustomTarget(output + '_h', state.subdir, state.subproject, custom_kwargs)
h_cmd += ['--pragma-once']
header = build.CustomTarget(
output + '_h',
state.subdir,
state.subproject,
h_cmd,
sources,
[header_file],
install=install_header,
install_dir=[kwargs['install_dir']] if kwargs['install_dir'] else [],
capture=capture,
depend_files=kwargs['depend_files'],
)
rv = [body, header]
return ModuleReturnValue(rv, rv)
@ -2021,24 +2059,25 @@ class GnomeModule(ExtensionModule):
cmd.append(gir_file)
vapi_output = library + '.vapi'
custom_kwargs = {
'command': cmd,
'input': inputs,
'output': vapi_output,
'depends': vapi_depends,
}
datadir = state.environment.coredata.get_option(mesonlib.OptionKey('datadir'))
assert isinstance(datadir, str), 'for mypy'
install_dir = kwargs['install_dir'] or os.path.join(datadir, 'vala', 'vapi')
custom_kwargs['install'] = kwargs['install']
custom_kwargs['install_dir'] = install_dir
custom_kwargs['packages'] = packages
if kwargs['install']:
# We shouldn't need this locally but we install it
deps_target = self._generate_deps(state, library, vapi_packages, install_dir)
created_values.append(deps_target)
vapi_target = VapiTarget(vapi_output, state.subdir, state.subproject, custom_kwargs)
vapi_target = VapiTarget(
vapi_output,
state.subdir,
state.subproject,
command=cmd,
sources=inputs,
outputs=[vapi_output],
extra_depends=vapi_depends,
install=kwargs['install'],
install_dir=[install_dir],
)
# So to try our best to get this to just work we need:
# - link with with the correct library

@ -344,8 +344,9 @@ class HotdocTargetBuilder:
extra_assets=self._extra_assets,
subprojects=self._subprojects,
command=target_cmd,
depends=self._dependencies,
output=fullname,
extra_depends=self._dependencies,
outputs=[fullname],
sources=[],
depfile=os.path.basename(depfile),
build_by_default=self.build_by_default)
@ -379,7 +380,7 @@ class HotdocTargetHolder(CustomTargetHolder):
class HotdocTarget(build.CustomTarget):
def __init__(self, name, subdir, subproject, hotdoc_conf, extra_extension_paths, extra_assets,
subprojects, **kwargs):
super().__init__(name, subdir, subproject, kwargs, absolute_paths=True)
super().__init__(name, subdir, subproject, **kwargs, absolute_paths=True)
self.hotdoc_conf = hotdoc_conf
self.extra_extension_paths = extra_extension_paths
self.extra_assets = extra_assets

@ -188,18 +188,18 @@ class I18nModule(ExtensionModule):
if build_by_default is None:
build_by_default = kwargs['install']
real_kwargs = {
'build_by_default': build_by_default,
'command': command,
'install': kwargs['install'],
'install_dir': kwargs['install_dir'],
'output': kwargs['output'],
'input': kwargs['input'],
'install_tag': kwargs['install_tag'],
}
ct = build.CustomTarget('', state.subdir, state.subproject,
T.cast(T.Dict[str, T.Any], real_kwargs))
ct = build.CustomTarget(
'',
state.subdir,
state.subproject,
command,
kwargs['input'],
kwargs['output'],
build_by_default=build_by_default,
install=kwargs['install'],
install_dir=kwargs['install_dir'],
install_tag=kwargs['install_tag'],
)
return ModuleReturnValue(ct, [ct])
@ -258,18 +258,21 @@ class I18nModule(ExtensionModule):
for l in languages:
po_file = mesonlib.File.from_source_file(state.environment.source_dir,
state.subdir, l+'.po')
gmo_kwargs = {'command': ['msgfmt', '@INPUT@', '-o', '@OUTPUT@'],
'input': po_file,
'output': packagename+'.mo',
'install': install,
# We have multiple files all installed as packagename+'.mo' in different install subdirs.
# What we really wanted to do, probably, is have a rename: kwarg, but that's not available
# to custom_targets. Crude hack: set the build target's subdir manually.
# Bonus: the build tree has something usable as an uninstalled bindtextdomain() target dir.
'install_dir': path.join(install_dir, l, 'LC_MESSAGES'),
'install_tag': 'i18n',
}
gmotarget = build.CustomTarget(f'{packagename}-{l}.mo', path.join(state.subdir, l, 'LC_MESSAGES'), state.subproject, gmo_kwargs)
gmotarget = build.CustomTarget(
f'{packagename}-{l}.mo',
path.join(state.subdir, l, 'LC_MESSAGES'),
state.subproject,
['msgfmt', '@INPUT@', '-o', '@OUTPUT@'],
[po_file],
[f'{packagename}.mo'],
install=install,
# We have multiple files all installed as packagename+'.mo' in different install subdirs.
# What we really wanted to do, probably, is have a rename: kwarg, but that's not available
# to custom_targets. Crude hack: set the build target's subdir manually.
# Bonus: the build tree has something usable as an uninstalled bindtextdomain() target dir.
install_dir=[path.join(install_dir, l, 'LC_MESSAGES')],
install_tag=['i18n'],
)
targets.append(gmotarget)
gmotargets.append(gmotarget)
@ -331,19 +334,19 @@ class I18nModule(ExtensionModule):
if build_by_default is None:
build_by_default = kwargs['install']
real_kwargs = {
'build_by_default': build_by_default,
'command': command,
'depends': mo_targets,
'install': kwargs['install'],
'install_dir': kwargs['install_dir'],
'output': kwargs['output'],
'input': kwargs['input'],
'install_tag': kwargs['install_tag'],
}
ct = build.CustomTarget('', state.subdir, state.subproject,
T.cast(T.Dict[str, T.Any], real_kwargs))
ct = build.CustomTarget(
'',
state.subdir,
state.subproject,
command,
kwargs['input'],
kwargs['output'],
build_by_default=build_by_default,
extra_depends=mo_targets,
install=kwargs['install'],
install_dir=kwargs['install_dir'],
install_tag=kwargs['install_tag'],
)
return ModuleReturnValue(ct, [ct])

@ -51,20 +51,22 @@ class JavaModule(ExtensionModule):
else:
header = f'{pathlib.Path(file.fname).stem}.h'
ct_kwargs = {
'input': file,
'output': header,
'command': [
target = CustomTarget(
os.path.basename(header),
state.subdir,
state.subproject,
[
self.javac.exelist[0],
'-d',
'@PRIVATE_DIR@',
'-h',
state.subdir,
'@INPUT@',
]
}
target = CustomTarget(os.path.basename(header), state.subdir, state.subproject, backend=state.backend, kwargs=ct_kwargs)
],
[file],
[header],
backend=state.backend,
)
# It is only known that 1.8.0 won't pre-create the directory. 11 and 16
# do not exhibit this behavior.
if version_compare(self.javac.version, '1.8.0'):

@ -328,14 +328,16 @@ class QtBaseModule(ExtensionModule):
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.tools['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)
res_target = build.CustomTarget(
name,
state.subdir,
state.subproject,
self.tools['rcc'].get_command() + ['-name', name, '-o', '@OUTPUT@'] + extra_args + ['@INPUT@'] + DEPFILE_ARGS,
sources,
[f'{name}.cpp'],
depend_files=qrc_deps,
depfile=f'{name}.d',
)
targets.append(res_target)
else:
for rcc_file in sources:
@ -345,14 +347,16 @@ class QtBaseModule(ExtensionModule):
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.tools['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)
res_target = build.CustomTarget(
name,
state.subdir,
state.subproject,
self.tools['rcc'].get_command() + ['-name', '@BASENAME@', '-o', '@OUTPUT@'] + extra_args + ['@INPUT@'] + DEPFILE_ARGS,
[rcc_file],
[f'{name}.cpp'],
depend_files=qrc_deps,
depfile=f'{name}.d',
)
targets.append(res_target)
return targets
@ -570,16 +574,19 @@ class QtBaseModule(ExtensionModule):
ts = os.path.basename(ts)
else:
outdir = state.subdir
cmd = [self.tools['lrelease'], '@INPUT@', '-qm', '@OUTPUT@']
lrelease_kwargs: T.Dict[str, T.Any] = {
'output': '@BASENAME@.qm',
'input': ts,
'install': kwargs['install'],
'install_dir': install_dir or [],
'install_tag': 'i18n',
'build_by_default': kwargs['build_by_default'],
'command': cmd}
lrelease_target = build.CustomTarget(f'qt{self.qt_version}-compile-{ts}', outdir, state.subproject, lrelease_kwargs)
cmd: T.List[T.Union[ExternalProgram, str]] = [self.tools['lrelease'], '@INPUT@', '-qm', '@OUTPUT@']
lrelease_target = build.CustomTarget(
f'qt{self.qt_version}-compile-{ts}',
outdir,
state.subproject,
cmd,
[ts],
['@BASENAME@.qm'],
install=kwargs['install'],
install_dir=install_dir,
install_tag=['i18n'],
build_by_default=kwargs['build_by_default'],
)
translations.append(lrelease_target)
if qresource:
return ModuleReturnValue(results.return_value[0], [results.new_objects, translations])

@ -227,15 +227,16 @@ class ExternalProject(NewExtensionModule):
if self.verbose:
cmd.append('--verbose')
target_kwargs = {'output': f'{self.name}.stamp',
'depfile': f'{self.name}.d',
'command': cmd + ['@OUTPUT@', '@DEPFILE@'],
'console': True,
}
self.target = build.CustomTarget(self.name,
self.subdir.as_posix(),
self.subproject,
target_kwargs)
self.target = build.CustomTarget(
self.name,
self.subdir.as_posix(),
self.subproject,
cmd + ['@OUTPUT@', '@DEPFILE@'],
[],
[f'{self.name}.stamp'],
depfile=f'{self.name}.d',
console=True,
)
idir = build.InstallDir(self.subdir.as_posix(),
Path('dist', self.rel_prefix).as_posix(),

@ -212,18 +212,16 @@ class RustModule(ExtensionModule):
f'rustmod-bindgen-{name}'.replace('/', '_'),
state.subdir,
state.subproject,
{
'input': header,
'output': kwargs['output'],
'command': self._bindgen_bin.get_command() + [
'@INPUT@', '--output',
os.path.join(state.environment.build_dir, '@OUTPUT@')] +
kwargs['args'] + ['--'] + kwargs['c_args'] + inc_strs +
['-MD', '-MQ', '@INPUT@', '-MF', '@DEPFILE@'],
'depfile': '@PLAINNAME@.d',
'depends': depends,
'depend_files': depend_files,
},
self._bindgen_bin.get_command() + [
'@INPUT@', '--output',
os.path.join(state.environment.build_dir, '@OUTPUT@')] +
kwargs['args'] + ['--'] + kwargs['c_args'] + inc_strs +
['-MD', '-MQ', '@INPUT@', '-MF', '@DEPFILE@'],
[header],
[kwargs['output']],
depfile='@PLAINNAME@.d',
extra_depends=depends,
depend_files=depend_files,
backend=state.backend,
)

@ -181,26 +181,25 @@ class WindowsModule(ExtensionModule):
command: T.List[T.Union[str, ExternalProgram]] = []
command.append(rescomp)
command.extend(res_args)
res_kwargs: 'RcKwargs' = {
'output': output,
'input': [src],
'depfile': None,
'depend_files': wrc_depend_files,
'depends': wrc_depends,
'command': [],
}
depfile: T.Optional[str] = None
# instruct binutils windres to generate a preprocessor depfile
if rescomp_type == ResourceCompilerType.windres:
res_kwargs['depfile'] = f'{output}.d'
depfile = f'{output}.d'
command.extend(['--preprocessor-arg=-MD',
'--preprocessor-arg=-MQ@OUTPUT@',
'--preprocessor-arg=-MF@DEPFILE@'])
res_kwargs['command'] = command
res_targets.append(build.CustomTarget(name_formatted, state.subdir, state.subproject, res_kwargs))
res_targets.append(build.CustomTarget(
name_formatted,
state.subdir,
state.subproject,
command,
[src],
[output],
depfile=depfile,
depend_files=wrc_depend_files,
extra_depends=wrc_depends,
))
return ModuleReturnValue(res_targets, [res_targets])

@ -1,7 +1,7 @@
{
"stdout": [
{
"line": "test cases/failing/41 custom target plainname many inputs/meson.build:5:0: ERROR: Output cannot contain @PLAINNAME@ or @BASENAME@ when there is more than one input (we can't know which to use)"
"line": "test cases/failing/41 custom target plainname many inputs/meson.build:5:0: ERROR: custom_target: output cannot containe \"@PLAINNAME@\" or \"@BASENAME@\" when there is more than one input (we can't know which to use)"
}
]
}

Loading…
Cancel
Save