From cbca1919481902efbd5dadda3cc80db84fd75f0c Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Thu, 21 Sep 2023 11:21:11 -0700 Subject: interpreter: Handle BuildTarget.vala_args as Files in the interpreter 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. --- docs/yaml/functions/_build_target_base.yaml | 5 ++ manual tests/7 vala composite widgets/meson.build | 21 ------- .../7 vala composite widgets/my-resources.xml | 6 -- manual tests/7 vala composite widgets/mywidget.ui | 70 ---------------------- .../7 vala composite widgets/mywidget.vala | 41 ------------- mesonbuild/backend/backends.py | 2 +- mesonbuild/backend/ninjabackend.py | 18 ++---- mesonbuild/backend/vs2010backend.py | 6 +- mesonbuild/build.py | 5 +- mesonbuild/interpreter/interpreter.py | 41 +++++++++++++ mesonbuild/interpreter/kwargs.py | 3 +- .../27 file as command line argument/meson.build | 21 +++++++ .../my-resources.xml | 6 ++ .../27 file as command line argument/mywidget.ui | 70 ++++++++++++++++++++++ .../27 file as command line argument/mywidget.vala | 41 +++++++++++++ 15 files changed, 198 insertions(+), 158 deletions(-) delete mode 100644 manual tests/7 vala composite widgets/meson.build delete mode 100644 manual tests/7 vala composite widgets/my-resources.xml delete mode 100644 manual tests/7 vala composite widgets/mywidget.ui delete mode 100644 manual tests/7 vala composite widgets/mywidget.vala create mode 100644 test cases/vala/27 file as command line argument/meson.build create mode 100644 test cases/vala/27 file as command line argument/my-resources.xml create mode 100644 test cases/vala/27 file as command line argument/mywidget.ui create mode 100644 test cases/vala/27 file as command line argument/mywidget.vala diff --git a/docs/yaml/functions/_build_target_base.yaml b/docs/yaml/functions/_build_target_base.yaml index 3f0e88158..1db49a531 100644 --- a/docs/yaml/functions/_build_target_base.yaml +++ b/docs/yaml/functions/_build_target_base.yaml @@ -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. diff --git a/manual tests/7 vala composite widgets/meson.build b/manual tests/7 vala composite widgets/meson.build deleted file mode 100644 index 579ca5198..000000000 --- a/manual tests/7 vala composite widgets/meson.build +++ /dev/null @@ -1,21 +0,0 @@ -project('composite', 'vala', 'c') -gnome = import('gnome') -deps = [ - dependency('glib-2.0', version : '>=2.38'), - dependency('gobject-2.0'), - dependency('gtk+-3.0'), -] -res = files('my-resources.xml') -gres = gnome.compile_resources( - 'my', res, - source_dir : '.', -) -executable( - 'demo', - sources : [ - 'mywidget.vala', - gres, - ], - dependencies : deps, - vala_args : ['--gresources', res], -) diff --git a/manual tests/7 vala composite widgets/my-resources.xml b/manual tests/7 vala composite widgets/my-resources.xml deleted file mode 100644 index b5743c193..000000000 --- a/manual tests/7 vala composite widgets/my-resources.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - mywidget.ui - - diff --git a/manual tests/7 vala composite widgets/mywidget.ui b/manual tests/7 vala composite widgets/mywidget.ui deleted file mode 100644 index 2d6286ca2..000000000 --- a/manual tests/7 vala composite widgets/mywidget.ui +++ /dev/null @@ -1,70 +0,0 @@ - - - - - diff --git a/manual tests/7 vala composite widgets/mywidget.vala b/manual tests/7 vala composite widgets/mywidget.vala deleted file mode 100644 index 68eaecc27..000000000 --- a/manual tests/7 vala composite widgets/mywidget.vala +++ /dev/null @@ -1,41 +0,0 @@ -using Gtk; - -[GtkTemplate (ui = "/org/foo/my/mywidget.ui")] -public class MyWidget : Box { - public string text { - get { return entry.text; } - set { entry.text = value; } - } - - [GtkChild] - private Entry entry; - - public MyWidget (string text) { - this.text = text; - } - - [GtkCallback] - private void on_button_clicked (Button button) { - print ("The button was clicked with entry text: %s\n", entry.text); - } - - [GtkCallback] - private void on_entry_changed (Editable editable) { - print ("The entry text changed: %s\n", entry.text); - - notify_property ("text"); - } -} - -void main(string[] args) { - Gtk.init (ref args); - var win = new Window(); - win.destroy.connect (Gtk.main_quit); - - var widget = new MyWidget ("The entry text!"); - - win.add (widget); - win.show_all (); - - Gtk.main (); -} diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index a8bf387f9..dd9e6ee6c 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -1475,7 +1475,7 @@ class Backend: 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): diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 29883bac7..d4d4e2ff6 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -1151,7 +1151,7 @@ class NinjaBackend(backends.Backend): 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: @@ -1214,7 +1214,7 @@ class NinjaBackend(backends.Backend): 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()) @@ -1712,18 +1712,10 @@ class NinjaBackend(backends.Backend): 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) @@ -2622,7 +2614,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) 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]) diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index c9c21a135..b9ada532b 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -187,7 +187,7 @@ class Vs2010Backend(backends.Backend): 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] @@ -699,7 +699,7 @@ class Vs2010Backend(backends.Backend): (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 @@ -738,7 +738,7 @@ class Vs2010Backend(backends.Backend): # 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)) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 8208fa0d9..9f0abf539 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -735,6 +735,7 @@ class BuildTarget(Target): 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 @@ -746,7 +747,7 @@ class BuildTarget(Target): # 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] = [] @@ -1278,7 +1279,7 @@ class BuildTarget(Target): 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) diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 0b6ccef22..29eaed202 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -3230,6 +3230,46 @@ class Interpreter(InterpreterBase, HoldableObject): 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 `_args : args`, but in the + build layer we store these in a single dictionary as `{: 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: ... @@ -3295,6 +3335,7 @@ class Interpreter(InterpreterBase, HoldableObject): 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'. diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index 241a08b76..26ecb4ef9 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -7,7 +7,7 @@ from __future__ import annotations 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 @@ -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): diff --git a/test cases/vala/27 file as command line argument/meson.build b/test cases/vala/27 file as command line argument/meson.build new file mode 100644 index 000000000..579ca5198 --- /dev/null +++ b/test cases/vala/27 file as command line argument/meson.build @@ -0,0 +1,21 @@ +project('composite', 'vala', 'c') +gnome = import('gnome') +deps = [ + dependency('glib-2.0', version : '>=2.38'), + dependency('gobject-2.0'), + dependency('gtk+-3.0'), +] +res = files('my-resources.xml') +gres = gnome.compile_resources( + 'my', res, + source_dir : '.', +) +executable( + 'demo', + sources : [ + 'mywidget.vala', + gres, + ], + dependencies : deps, + vala_args : ['--gresources', res], +) diff --git a/test cases/vala/27 file as command line argument/my-resources.xml b/test cases/vala/27 file as command line argument/my-resources.xml new file mode 100644 index 000000000..b5743c193 --- /dev/null +++ b/test cases/vala/27 file as command line argument/my-resources.xml @@ -0,0 +1,6 @@ + + + + mywidget.ui + + diff --git a/test cases/vala/27 file as command line argument/mywidget.ui b/test cases/vala/27 file as command line argument/mywidget.ui new file mode 100644 index 000000000..2d6286ca2 --- /dev/null +++ b/test cases/vala/27 file as command line argument/mywidget.ui @@ -0,0 +1,70 @@ + + + + + diff --git a/test cases/vala/27 file as command line argument/mywidget.vala b/test cases/vala/27 file as command line argument/mywidget.vala new file mode 100644 index 000000000..68eaecc27 --- /dev/null +++ b/test cases/vala/27 file as command line argument/mywidget.vala @@ -0,0 +1,41 @@ +using Gtk; + +[GtkTemplate (ui = "/org/foo/my/mywidget.ui")] +public class MyWidget : Box { + public string text { + get { return entry.text; } + set { entry.text = value; } + } + + [GtkChild] + private Entry entry; + + public MyWidget (string text) { + this.text = text; + } + + [GtkCallback] + private void on_button_clicked (Button button) { + print ("The button was clicked with entry text: %s\n", entry.text); + } + + [GtkCallback] + private void on_entry_changed (Editable editable) { + print ("The entry text changed: %s\n", entry.text); + + notify_property ("text"); + } +} + +void main(string[] args) { + Gtk.init (ref args); + var win = new Window(); + win.destroy.connect (Gtk.main_quit); + + var widget = new MyWidget ("The entry text!"); + + win.add (widget); + win.show_all (); + + Gtk.main (); +} -- cgit v1.2.3