diff options
author | Stas Sergeev <stsp@users.sourceforge.net> | 2024-05-07 21:46:55 +0300 |
---|---|---|
committer | Dylan Baker <dylan@pnwbakers.com> | 2024-05-09 12:27:35 -0700 |
commit | cfd57180eef9036c7167c5682b9f3055a540fccc (patch) | |
tree | 65f8ed46c385af05d6387aec6d16b1fcd311564f | |
parent | f8aefe20703e3d64710fa675d511f9bef77dc32a (diff) | |
download | meson-cfd57180eef9036c7167c5682b9f3055a540fccc.zip meson-cfd57180eef9036c7167c5682b9f3055a540fccc.tar.gz meson-cfd57180eef9036c7167c5682b9f3055a540fccc.tar.bz2 |
implement @PLAINNAME0@ and @BASENAME0@
@PLAINNAME@ and @BASENAME@ cannot be used in custom_target()
with multiple inputs. For those, similar macros are needed
with an index.
Fixes #13164
-rw-r--r-- | docs/markdown/snippets/pln_bsn_support.md | 11 | ||||
-rw-r--r-- | docs/yaml/functions/configure_file.yaml | 4 | ||||
-rw-r--r-- | docs/yaml/functions/custom_target.yaml | 2 | ||||
-rw-r--r-- | mesonbuild/interpreter/interpreter.py | 10 | ||||
-rw-r--r-- | mesonbuild/utils/universal.py | 5 | ||||
-rw-r--r-- | unittests/internaltests.py | 11 |
6 files changed, 39 insertions, 4 deletions
diff --git a/docs/markdown/snippets/pln_bsn_support.md b/docs/markdown/snippets/pln_bsn_support.md new file mode 100644 index 0000000..394339f --- /dev/null +++ b/docs/markdown/snippets/pln_bsn_support.md @@ -0,0 +1,11 @@ +## Support of indexed `@PLAINNAME@` and `@BASENAME@` + +In `custom_target()` and `configure_file()` with multiple inputs, +it is now possible to specify index for `@PLAINNAME@` and `@BASENAME@` +macros in `output`: +``` +custom_target('target_name', + output: '@PLAINNAME0@.dl', + input: [dep1, dep2], + command: cmd) +``` diff --git a/docs/yaml/functions/configure_file.yaml b/docs/yaml/functions/configure_file.yaml index 34cb3c1..20b96aa 100644 --- a/docs/yaml/functions/configure_file.yaml +++ b/docs/yaml/functions/configure_file.yaml @@ -123,7 +123,9 @@ kwargs: type: str description: | The output file name. *(since 0.41.0)* may contain - `@PLAINNAME@` or `@BASENAME@` substitutions. In configuration mode, + `@PLAINNAME@` or `@BASENAME@` substitutions, as well as *(since 1.5.0)* + their indexed versions, like `@PLAINNAME0@` or `@BASENAME0@`. + In configuration mode, the permissions of the input file (if it is specified) are copied to the output file. diff --git a/docs/yaml/functions/custom_target.yaml b/docs/yaml/functions/custom_target.yaml index cd5c60e..585d260 100644 --- a/docs/yaml/functions/custom_target.yaml +++ b/docs/yaml/functions/custom_target.yaml @@ -31,7 +31,9 @@ description: | - `@OUTDIR@`: the full path to the directory where the output(s) must be written - `@DEPFILE@`: the full path to the dependency file passed to `depfile` - `@PLAINNAME@`: the input filename, without a path + - `@PLAINNAME0@` `@PLAINNAME1@` `...` *(since 1.5.0)*: the input filename without a path, with the specified array index in `input` - `@BASENAME@`: the input filename, with extension removed + - `@BASENAME0@` `@BASENAME1@` `...` *(since 1.5.0)*: the input filename with extension removed, with the specified array index in `input` - `@PRIVATE_DIR@` *(since 0.50.1)*: path to a directory where the custom target must store all its intermediate files. - `@SOURCE_ROOT@`: the path to the root of the source tree. Depending on the backend, this may be an absolute or a relative to current workdir path. diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index f6b4cf4..08bd054 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -1983,17 +1983,23 @@ class Interpreter(InterpreterBase, HoldableObject): def func_subdir_done(self, node: mparser.BaseNode, args: TYPE_var, kwargs: TYPE_kwargs) -> T.NoReturn: raise SubdirDoneRequest() - @staticmethod - def _validate_custom_target_outputs(has_multi_in: bool, outputs: T.Iterable[str], name: str) -> None: + def _validate_custom_target_outputs(self, 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. """ + inregex: T.List[str] = ['@PLAINNAME[0-9]+@', '@BASENAME[0-9]+@'] + from ..utils.universal import iter_regexin_iter for out in outputs: + match = iter_regexin_iter(inregex, [out]) if has_multi_in and ('@PLAINNAME@' in out or '@BASENAME@' in out): raise InvalidArguments(f'{name}: output cannot contain "@PLAINNAME@" or "@BASENAME@" ' 'when there is more than one input (we can\'t know which to use)') + elif match: + FeatureNew.single_use( + f'{match} in output', '1.5.0', + self.subproject) @typed_pos_args('custom_target', optargs=[str]) @typed_kwargs( diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index ce9afd9..c831169 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -1744,6 +1744,8 @@ def get_filenames_templates_dict(inputs: T.List[str], outputs: T.List[str]) -> T If there is more than one input file, the following keys are also created: @INPUT0@, @INPUT1@, ... one for each input file + @PLAINNAME0@, @PLAINNAME1@, ... one for each input file + @BASENAME0@, @BASENAME1@, ... one for each input file If there is more than one output file, the following keys are also created: @@ -1757,6 +1759,9 @@ def get_filenames_templates_dict(inputs: T.List[str], outputs: T.List[str]) -> T for (ii, vv) in enumerate(inputs): # Write out @INPUT0@, @INPUT1@, ... values[f'@INPUT{ii}@'] = vv + plain = os.path.basename(vv) + values[f'@PLAINNAME{ii}@'] = plain + values[f'@BASENAME{ii}@'] = os.path.splitext(plain)[0] if len(inputs) == 1: # Just one value, substitute @PLAINNAME@ and @BASENAME@ values['@PLAINNAME@'] = plain = os.path.basename(inputs[0]) diff --git a/unittests/internaltests.py b/unittests/internaltests.py index 0f2622e..411c97b 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -287,6 +287,7 @@ class InternalTests(unittest.TestCase): outputs = [] ret = dictfunc(inputs, outputs) d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], + '@PLAINNAME0@': 'foo.c.in', '@BASENAME0@': 'foo.c', '@PLAINNAME@': 'foo.c.in', '@BASENAME@': 'foo.c'} # Check dictionary self.assertEqual(ret, d) @@ -309,6 +310,7 @@ class InternalTests(unittest.TestCase): outputs = ['out.c'] ret = dictfunc(inputs, outputs) d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], + '@PLAINNAME0@': 'foo.c.in', '@BASENAME0@': 'foo.c', '@PLAINNAME@': 'foo.c.in', '@BASENAME@': 'foo.c', '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTDIR@': '.'} # Check dictionary @@ -330,6 +332,7 @@ class InternalTests(unittest.TestCase): outputs = ['dir/out.c'] ret = dictfunc(inputs, outputs) d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], + '@PLAINNAME0@': 'foo.c.in', '@BASENAME0@': 'foo.c', '@PLAINNAME@': 'foo.c.in', '@BASENAME@': 'foo.c', '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTDIR@': 'dir'} # Check dictionary @@ -339,7 +342,9 @@ class InternalTests(unittest.TestCase): inputs = ['bar/foo.c.in', 'baz/foo.c.in'] outputs = [] ret = dictfunc(inputs, outputs) - d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@INPUT1@': inputs[1]} + d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@INPUT1@': inputs[1], + '@PLAINNAME0@': 'foo.c.in', '@PLAINNAME1@': 'foo.c.in', + '@BASENAME0@': 'foo.c', '@BASENAME1@': 'foo.c'} # Check dictionary self.assertEqual(ret, d) # Check substitutions @@ -376,6 +381,8 @@ class InternalTests(unittest.TestCase): outputs = ['dir/out.c'] ret = dictfunc(inputs, outputs) d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@INPUT1@': inputs[1], + '@PLAINNAME0@': 'foo.c.in', '@PLAINNAME1@': 'foo.c.in', + '@BASENAME0@': 'foo.c', '@BASENAME1@': 'foo.c', '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTDIR@': 'dir'} # Check dictionary self.assertEqual(ret, d) @@ -402,6 +409,8 @@ class InternalTests(unittest.TestCase): outputs = ['dir/out.c', 'dir/out2.c'] ret = dictfunc(inputs, outputs) d = {'@INPUT@': inputs, '@INPUT0@': inputs[0], '@INPUT1@': inputs[1], + '@PLAINNAME0@': 'foo.c.in', '@PLAINNAME1@': 'foo.c.in', + '@BASENAME0@': 'foo.c', '@BASENAME1@': 'foo.c', '@OUTPUT@': outputs, '@OUTPUT0@': outputs[0], '@OUTPUT1@': outputs[1], '@OUTDIR@': 'dir'} # Check dictionary |