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

Add a file_argument function #12287

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions data/syntax-highlighting/vim/syntax/meson.vim
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ syn keyword mesonBuiltin
\ error
\ executable
\ files
\ file_argument
\ find_program
\ generator
\ get_option
Expand Down
18 changes: 18 additions & 0 deletions docs/markdown/snippets/file_argument.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## New file_argument() function

Sometimes arguments need to be passed as a single string, but that string needs
to contain a File as part of the string. Consider how linker scripts work with GCC:
`-Wl,--version-script,<file>`. This is painful to deal with when the `<file>` is
a `files()` object. with `file_argument()` this becomes easier.

```meson
build_target(
...,
c_args : [file_argument('--file-arg=', files('foo.file'))],
link_args : [file_argument('-Wl,--version-script,', file('file.map'))],
)
```

Meson will automatically create the correct strings, relative to the build
directory, and will automatically add the file to the correct depends, so that
compilation and/or linking will correctly depend on that file.
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
32 changes: 32 additions & 0 deletions docs/yaml/functions/file_argument.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: file_argument
since: 1.3.0
returns: file_arg
description: |
Passes a string argument that must be joined to a file path in [[@build_tgt]]

This allows passing [[@file]] objects to the `<lang>_args` and `link_args`
parameters of a [[@build_tgt]]. Once passed they will be converted to a string
argument, and the [[@file]] will be added to the appropriate dependencies
(either build or link).

example: |
This is particularly useful when working with linker scripts:

```meson
tgt = build_tgt(
...,
link_with : file_argument('-Wl,--linker-script,' files('link.map')),
)
```

In this case Meson will pass `-Wl,--linker-script,link.map` (or a relative
path for `link.map`), and will add it to the link dependencies for `tgt`

posargs:
arg:
type: str
description: The string part of the argument

file:
type: file
description: The file part of the argument
3 changes: 3 additions & 0 deletions docs/yaml/objects/file_arg.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: file_arg
long_name: file argument
description: Opaque object returned by [[file_argument]]
1 change: 1 addition & 0 deletions mesonbuild/ast/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ def __init__(self, source_root: str, subdir: str, subproject: str, visitors: T.O
'add_languages': self.func_do_nothing,
'declare_dependency': self.func_do_nothing,
'files': self.func_do_nothing,
'file_argument': self.func_do_nothing,
'executable': self.func_do_nothing,
'static_library': self.func_do_nothing,
'shared_library': self.func_do_nothing,
Expand Down
2 changes: 1 addition & 1 deletion mesonbuild/backend/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -1461,7 +1461,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
31 changes: 12 additions & 19 deletions mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1068,7 +1068,7 @@ def should_use_dyndeps_for_target(self, target: 'build.BuildTarget') -> bool:
return True
if 'cpp' not in target.compilers:
return False
if '-fmodules-ts' in target.extra_args.get('cpp', []):
if '-fmodules-ts' in target.extra_args['cpp']:
return True
# Currently only the preview version of Visual Studio is supported.
cpp = target.compilers['cpp']
Expand Down 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 @@ -1461,8 +1461,8 @@ def generate_cs_target(self, target: build.BuildTarget):
src_list = target.get_sources()
compiler = target.compilers['cs']
rel_srcs = [os.path.normpath(s.rel_to_builddir(self.build_to_src)) for s in src_list]
deps = []
commands = compiler.compiler_args(target.extra_args.get('cs', []))
deps = self.get_target_depend_files(target)
commands = compiler.compiler_args(target.extra_args['cs'])
commands += compiler.get_buildtype_args(buildtype)
commands += compiler.get_optimization_args(target.get_option(OptionKey('optimization')))
commands += compiler.get_debug_args(target.get_option(OptionKey('debug')))
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 @@ -1886,6 +1878,7 @@ def generate_rust_target(self, target: build.BuildTarget) -> None:
os.path.join(t.subdir, t.get_filename())
for t in itertools.chain(target.link_targets, target.link_whole_targets)
]
deps.extend(self.get_target_depend_files(target))

# Dependencies for rust-project.json
project_deps: T.List[RustDep] = []
Expand Down Expand Up @@ -2204,8 +2197,8 @@ def determine_swift_dep_modules(self, target):
result.append(self.swift_module_file_name(l))
return result

def get_swift_link_deps(self, target):
result = []
def get_swift_link_deps(self, target: build.BuildTarget) -> T.List[str]:
result = self.get_target_depend_files(target)
for l in target.link_targets:
result.append(self.get_target_filename(l))
return result
Expand Down Expand Up @@ -2622,7 +2615,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 Expand Up @@ -3043,7 +3036,7 @@ def generate_single_compile(self, target: build.BuildTarget, src,
pch_dep = arr

compiler_name = self.compiler_to_rule_name(compiler)
extra_deps = []
extra_deps = self.get_target_depend_files(target)
if compiler.get_language() == 'fortran':
# Can't read source file to scan for deps if it's generated later
# at build-time. Skip scanning for deps, and just set the module
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 @@ -698,7 +698,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 @@ -737,7 +737,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
35 changes: 16 additions & 19 deletions mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,14 @@ def get_target_macos_dylib_install_name(ld) -> str:
class InvalidArguments(MesonException):
pass


@dataclass
class FileArgument(HoldableObject):

arg: str
file: File


@dataclass(eq=False)
class DependencyOverride(HoldableObject):
dep: dependencies.Dependency
Expand Down Expand Up @@ -721,7 +729,7 @@ def __init__(
objects: T.List[ObjectTypes],
environment: environment.Environment,
compilers: T.Dict[str, 'Compiler'],
kwargs):
kwargs: T.Dict[str, T.Any]):
super().__init__(name, subdir, subproject, True, for_machine, environment, install=kwargs.get('install', False))
self.all_compilers = compilers
self.compilers: OrderedDict[str, Compiler] = OrderedDict()
Expand All @@ -732,6 +740,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 @@ -741,7 +750,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.DefaultDict[str, T.List[str]] = kwargs.get('language_args', defaultdict(list))
self.sources: T.List[File] = []
self.generated: T.List['GeneratedTypes'] = []
self.extra_files: T.List[File] = []
Expand Down Expand Up @@ -825,6 +834,8 @@ def check_unknown_kwargs(self, kwargs):
def check_unknown_kwargs_int(self, kwargs, known_kwargs):
unknowns = []
for k in kwargs:
if k == 'language_args':
continue
if k not in known_kwargs:
unknowns.append(k)
if len(unknowns) > 0:
Expand Down Expand Up @@ -1098,10 +1109,6 @@ def process_kwargs(self, kwargs):
self.process_kwargs_base(kwargs)
self.original_kwargs = kwargs

for lang in all_languages:
lang_args = extract_as_list(kwargs, f'{lang}_args')
self.add_compiler_args(lang, lang_args)

self.add_pch('c', extract_as_list(kwargs, 'c_pch'))
self.add_pch('cpp', extract_as_list(kwargs, 'cpp_pch'))

Expand Down Expand Up @@ -1265,8 +1272,8 @@ def get_filename(self) -> str:
def get_outputs(self) -> T.List[str]:
return self.outputs

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

@lru_cache(maxsize=None)
def get_dependencies(self) -> OrderedSet[Target]:
Expand Down Expand Up @@ -1525,16 +1532,6 @@ def add_include_dirs(self, args: T.Sequence['IncludeDirs'], set_is_system: T.Opt
ids = [IncludeDirs(x.get_curdir(), x.get_incdirs(), is_system, x.get_extra_build_dirs()) for x in ids]
self.include_dirs += ids

def add_compiler_args(self, language: str, args: T.List['FileOrString']) -> None:
args = listify(args)
for a in args:
if not isinstance(a, (str, File)):
raise InvalidArguments('A non-string passed to compiler args.')
if language in self.extra_args:
self.extra_args[language] += args
else:
self.extra_args[language] = args

def get_aliases(self) -> T.List[T.Tuple[str, str, str]]:
return []

Expand Down Expand Up @@ -2843,7 +2840,7 @@ def __init__(self, name: str, subdir: str, subproject: str, for_machine: Machine
raise InvalidArguments('structured sources are not supported in Java targets.')
self.filename = self.name + '.jar'
self.outputs = [self.filename]
self.java_args = kwargs.get('java_args', [])
self.java_args = self.extra_args['java']
self.main_class = kwargs.get('main_class', '')
self.java_resources: T.Optional[StructuredSources] = kwargs.get('java_resources', None)

Expand Down
Loading
Loading