Skip to content

Commit

Permalink
interpreter: Handle BuildTarget.vala_args as Files in the interpreter
Browse files Browse the repository at this point in the history
Way back in Meson 0.25, support was added to `vala_args` for Files.
Strangely, this was never added to any other language, though it's been
discussed before. For type safety, it makes more sense to handle this in
the interpreter level, and pass only strings into the build IR.

This is accomplished by adding a `depend_files` field to the
`BuildTarget` class (which is not exposed to the user), and adding the
depend files into that field, while converting the arguments to relative
string paths. This ensures both the proper build dependencies happen, as
well as that the arguments are always strings.
  • Loading branch information
dcbaker authored and eli-schwartz committed Oct 9, 2023
1 parent 8490eaa commit cbca191
Show file tree
Hide file tree
Showing 11 changed files with 60 additions and 20 deletions.
5 changes: 5 additions & 0 deletions docs/yaml/functions/_build_target_base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ kwargs:
compiler flags to use for the given language;
eg: `cpp_args` for C++
vala_args:
type: list[str | file]
description: |
Compiler flags for Vala. Unlike other languages this may contain Files
sources:
type: str | file | custom_tgt | custom_idx | generated_list | structured_src
description: Additional source files. Same as the source varargs.
Expand Down
2 changes: 1 addition & 1 deletion mesonbuild/backend/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -1475,7 +1475,7 @@ def get_custom_target_sources(self, target: build.CustomTarget) -> T.List[str]:
srcs += fname
return srcs

def get_custom_target_depend_files(self, target: build.CustomTarget, absolute_paths: bool = False) -> T.List[str]:
def get_target_depend_files(self, target: T.Union[build.CustomTarget, build.BuildTarget], absolute_paths: bool = False) -> T.List[str]:
deps: T.List[str] = []
for i in target.depend_files:
if isinstance(i, mesonlib.File):
Expand Down
18 changes: 5 additions & 13 deletions mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1151,7 +1151,7 @@ def generate_custom_target(self, target: build.CustomTarget):
self.custom_target_generator_inputs(target)
(srcs, ofilenames, cmd) = self.eval_custom_target_command(target)
deps = self.unwrap_dep_list(target)
deps += self.get_custom_target_depend_files(target)
deps += self.get_target_depend_files(target)
if target.build_always_stale:
deps.append('PHONY')
if target.depfile is None:
Expand Down Expand Up @@ -1214,7 +1214,7 @@ def generate_run_target(self, target: build.RunTarget):
elem.add_item('description', f'Running external command {target.name}{cmd_type}')
elem.add_item('pool', 'console')
deps = self.unwrap_dep_list(target)
deps += self.get_custom_target_depend_files(target)
deps += self.get_target_depend_files(target)
elem.add_dep(deps)
self.add_build(elem)
self.processed_targets.add(target.get_id())
Expand Down Expand Up @@ -1712,18 +1712,10 @@ def generate_vala_compile(self, target: build.BuildTarget) -> \
if isinstance(gensrc, modules.GResourceTarget):
gres_xml, = self.get_custom_target_sources(gensrc)
args += ['--gresources=' + gres_xml]
extra_args = []

for a in target.extra_args.get('vala', []):
if isinstance(a, File):
relname = a.rel_to_builddir(self.build_to_src)
extra_dep_files.append(relname)
extra_args.append(relname)
else:
extra_args.append(a)
dependency_vapis = self.determine_dep_vapis(target)
extra_dep_files += dependency_vapis
args += extra_args
extra_dep_files.extend(self.get_target_depend_files(target))
args += target.get_extra_args('vala')
element = NinjaBuildElement(self.all_outputs, valac_outputs,
self.compiler_to_rule_name(valac),
all_files + dependency_vapis)
Expand Down Expand Up @@ -2622,7 +2614,7 @@ def generate_genlist_for_target(self, genlist: build.GeneratedList, target: buil
exe = generator.get_exe()
infilelist = genlist.get_inputs()
outfilelist = genlist.get_outputs()
extra_dependencies = self.get_custom_target_depend_files(genlist)
extra_dependencies = self.get_target_depend_files(genlist)
for i, curfile in enumerate(infilelist):
if len(generator.outputs) == 1:
sole_output = os.path.join(self.get_target_private_dir(target), outfilelist[i])
Expand Down
6 changes: 3 additions & 3 deletions mesonbuild/backend/vs2010backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def generate_genlist_for_target(self, genlist: T.Union[build.GeneratedList, buil
else:
sole_output = ''
infilename = os.path.join(down, curfile.rel_to_builddir(self.build_to_src, target_private_dir))
deps = self.get_custom_target_depend_files(genlist, True)
deps = self.get_target_depend_files(genlist, True)
base_args = generator.get_arglist(infilename)
outfiles_rel = genlist.get_outputs_for(curfile)
outfiles = [os.path.join(target_private_dir, of) for of in outfiles_rel]
Expand Down Expand Up @@ -699,7 +699,7 @@ def gen_run_target_vcxproj(self, target: build.RunTarget, ofname: str, guid: str
(root, type_config) = self.create_basic_project(target.name,
temp_dir=target.get_id(),
guid=guid)
depend_files = self.get_custom_target_depend_files(target)
depend_files = self.get_target_depend_files(target)

if not target.command:
# This is an alias target and thus doesn't run any command. It's
Expand Down Expand Up @@ -738,7 +738,7 @@ def gen_custom_target_vcxproj(self, target: build.CustomTarget, ofname: str, gui
# from the target dir, not the build root.
target.absolute_paths = True
(srcs, ofilenames, cmd) = self.eval_custom_target_command(target, True)
depend_files = self.get_custom_target_depend_files(target, True)
depend_files = self.get_target_depend_files(target, True)
# Always use a wrapper because MSBuild eats random characters when
# there are many arguments.
tdir_abs = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target))
Expand Down
5 changes: 3 additions & 2 deletions mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,7 @@ def __init__(
self.link_language = kwargs.get('link_language')
self.link_targets: T.List[LibTypes] = []
self.link_whole_targets: T.List[T.Union[StaticLibrary, CustomTarget, CustomTargetIndex]] = []
self.depend_files: T.List[File] = []
self.link_depends = []
self.added_deps = set()
self.name_prefix_set = False
Expand All @@ -746,7 +747,7 @@ def __init__(
# as Vala which generates .vapi and .h besides the compiled output.
self.outputs = [self.filename]
self.pch: T.Dict[str, T.List[str]] = {}
self.extra_args: T.Dict[str, T.List['FileOrString']] = {}
self.extra_args: T.Dict[str, T.List[str]] = {}
self.sources: T.List[File] = []
self.generated: T.List['GeneratedTypes'] = []
self.extra_files: T.List[File] = []
Expand Down Expand Up @@ -1278,7 +1279,7 @@ def get_debug_filename(self) -> T.Optional[str]:
def get_outputs(self) -> T.List[str]:
return self.outputs

def get_extra_args(self, language):
def get_extra_args(self, language) -> T.List[str]:
return self.extra_args.get(language, [])

@lru_cache(maxsize=None)
Expand Down
41 changes: 41 additions & 0 deletions mesonbuild/interpreter/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3230,6 +3230,46 @@ def build_library(self, node, args, kwargs):
else:
raise InterpreterException(f'Unknown default_library value: {default_library}.')

def __convert_file_args(self, raw: T.List[mesonlib.FileOrString], allow_file: bool) -> T.Tuple[T.List[mesonlib.File], T.List[str]]:
"""Convert raw target arguments from File | str to File.
This removes files from the command line and replaces them with string
values, but adds the files to depends list
:param raw: the raw arguments
:return: A tuple of file dependencies and raw arguments
"""
depend_files: T.List[mesonlib.File] = []
args: T.List[str] = []
build_to_source = mesonlib.relpath(self.environment.get_source_dir(),
self.environment.get_build_dir())

for a in raw:
if isinstance(a, mesonlib.File):
if not allow_file:
raise InvalidArguments('File type arguments are only allowed for vala')
depend_files.append(a)
args.append(a.rel_to_builddir(build_to_source))
else:
args.append(a)

return depend_files, args

def __process_language_args(self, kwargs: T.Dict[str, T.List[mesonlib.FileOrString]]) -> None:
"""Convert split language args into a combined dictionary.
The Meson DSL takes arguments in the form `<lang>_args : args`, but in the
build layer we store these in a single dictionary as `{<lang>: args}`.
This function extracts the arguments from the DSL format and prepares
them for the IR.
"""
d = kwargs.setdefault('depend_files', [])

for l in compilers.all_languages:
deps, args = self.__convert_file_args(kwargs[f'{l}_args'], l == 'vala')
kwargs[f'{l}_args'] = args
d.extend(deps)

@T.overload
def build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType],
kwargs: kwtypes.Executable, targetclass: T.Type[build.Executable]) -> build.Executable: ...
Expand Down Expand Up @@ -3295,6 +3335,7 @@ def build_target_decorator_caller(self, node, args, kwargs):
mlog.debug('Unknown target type:', str(targetclass))
raise RuntimeError('Unreachable code')
self.kwarg_strings_to_includedirs(kwargs)
self.__process_language_args(kwargs)

# Filter out kwargs from other target types. For example 'soversion'
# passed to library() when default_library == 'static'.
Expand Down
3 changes: 2 additions & 1 deletion mesonbuild/interpreter/kwargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import typing as T

from typing_extensions import TypedDict, Literal, Protocol
from typing_extensions import TypedDict, Literal, Protocol, NotRequired

from .. import build
from .. import coredata
Expand Down Expand Up @@ -326,6 +326,7 @@ class _BaseBuildTarget(TypedDict):
"""

override_options: T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]]
depend_files: NotRequired[T.List[File]]


class _BuildTarget(_BaseBuildTarget):
Expand Down

0 comments on commit cbca191

Please sign in to comment.