From 03a0d3ddfb092ceb48f1a30fdf5e4b6af2890235 Mon Sep 17 00:00:00 2001 From: Dudemanguy Date: Sun, 6 Aug 2023 21:02:18 -0500 Subject: [PATCH] mcompile: add suffix as an additional parameter Since the previous commit allows for more scenarios with name collisions, it makes sense to expand the compile command so that it can also take into account suffixes. i.e. meson compile -C build foo.exe can now work if the executable has an exe suffix along with being named foo. --- docs/markdown/Commands.md | 7 +++- .../snippets/meson_compile_suffixes.md | 7 ++++ mesonbuild/mcompile.py | 40 ++++++++++++++++--- unittests/allplatformstests.py | 9 +++++ 4 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 docs/markdown/snippets/meson_compile_suffixes.md diff --git a/docs/markdown/Commands.md b/docs/markdown/Commands.md index efc316ce7fbb..3fcdedd03ca3 100644 --- a/docs/markdown/Commands.md +++ b/docs/markdown/Commands.md @@ -58,14 +58,17 @@ Builds a default or a specified target of a configured Meson project. *(since 0.55.0)* -`TARGET` has the following syntax `[PATH/]NAME[:TYPE]`, where: +`TARGET` has the following syntax `[PATH/]NAME.SUFFIX[:TYPE]`, where: - `NAME`: name of the target from `meson.build` (e.g. `foo` from `executable('foo', ...)`). +- `SUFFIX`: name of the suffix of the target from `meson.build` (e.g. `exe` from `executable('foo', suffix: 'exe', ...)`). - `PATH`: path to the target relative to the root `meson.build` file. Note: relative path for a target specified in the root `meson.build` is `./`. - `TYPE`: type of the target. Can be one of the following: 'executable', 'static_library', 'shared_library', 'shared_module', 'custom', 'alias', 'run', 'jar'. -`PATH` and/or `TYPE` can be omitted if the resulting `TARGET` can be +`PATH`, `SUFFIX`, and `TYPE` can all be omitted if the resulting `TARGET` can be used to uniquely identify the target in `meson.build`. +Note that `SUFFIX` did not exist prior to 1.3.0. + #### Backend specific arguments *(since 0.55.0)* diff --git a/docs/markdown/snippets/meson_compile_suffixes.md b/docs/markdown/snippets/meson_compile_suffixes.md new file mode 100644 index 000000000000..481e8adf4b92 --- /dev/null +++ b/docs/markdown/snippets/meson_compile_suffixes.md @@ -0,0 +1,7 @@ +## Meson compile command now accepts suffixes for TARGET + +The syntax for specifying a target for meson compile is now +`[PATH_TO_TARGET/]TARGET_NAME.TARGET_SUFFIX[:TARGET_TYPE]` where +`TARGET_SUFFIX` is the suffix argument given in the build target +within meson.build. It is optional and `TARGET_NAME` remains +sufficient if it uniquely resolves to one single target. diff --git a/mesonbuild/mcompile.py b/mesonbuild/mcompile.py index 19875c22a9cd..6721beb0b008 100644 --- a/mesonbuild/mcompile.py +++ b/mesonbuild/mcompile.py @@ -61,9 +61,11 @@ def parse_introspect_data(builddir: Path) -> T.Dict[str, T.List[dict]]: class ParsedTargetName: full_name = '' + base_name = '' name = '' type = '' path = '' + suffix = '' def __init__(self, target: str): self.full_name = target @@ -80,6 +82,13 @@ def __init__(self, target: str): else: self.name = split[0] + split = self.name.rsplit('.', 1) + if len(split) > 1: + self.base_name = split[0] + self.suffix = split[1] + else: + self.base_name = split[0] + @staticmethod def _is_valid_type(type: str) -> bool: # Amend docs in Commands.md when editing this list @@ -96,19 +105,32 @@ def _is_valid_type(type: str) -> bool: return type in allowed_types def get_target_from_intro_data(target: ParsedTargetName, builddir: Path, introspect_data: T.Dict[str, T.Any]) -> T.Dict[str, T.Any]: - if target.name not in introspect_data: + if target.name not in introspect_data and target.base_name not in introspect_data: raise MesonException(f'Can\'t invoke target `{target.full_name}`: target not found') intro_targets = introspect_data[target.name] + # if target.name doesn't find anything, try just the base name + if not intro_targets: + intro_targets = introspect_data[target.base_name] found_targets: T.List[T.Dict[str, T.Any]] = [] resolved_bdir = builddir.resolve() - if not target.type and not target.path: + if not target.type and not target.path and not target.suffix: found_targets = intro_targets else: for intro_target in intro_targets: + # Parse out the name from the id if needed + intro_target_name = intro_target['name'] + split = intro_target['id'].rsplit('@', 1) + if len(split) > 1: + split = split[0].split('@@', 1) + if len(split) > 1: + intro_target_name = split[1] + else: + intro_target_name = split[0] if ((target.type and target.type != intro_target['type'].replace(' ', '_')) or + (target.name != intro_target_name) or (target.path and intro_target['filename'] != 'no_name' and Path(target.path) != Path(intro_target['filename'][0]).relative_to(resolved_bdir).parent)): continue @@ -119,12 +141,20 @@ def get_target_from_intro_data(target: ParsedTargetName, builddir: Path, introsp elif len(found_targets) > 1: suggestions: T.List[str] = [] for i in found_targets: - p = Path(i['filename'][0]).relative_to(resolved_bdir).parent / i['name'] + i_name = i['name'] + split = i['id'].rsplit('@', 1) + if len(split) > 1: + split = split[0].split('@@', 1) + if len(split) > 1: + i_name = split[1] + else: + i_name = split[0] + p = Path(i['filename'][0]).relative_to(resolved_bdir).parent / i_name t = i['type'].replace(' ', '_') suggestions.append(f'- ./{p}:{t}') suggestions_str = '\n'.join(suggestions) raise MesonException(f'Can\'t invoke target `{target.full_name}`: ambiguous name.' - f'Add target type and/or path:\n{suggestions_str}') + f' Add target type and/or path:\n{suggestions_str}') return found_targets[0] @@ -278,7 +308,7 @@ def add_arguments(parser: 'argparse.ArgumentParser') -> None: metavar='TARGET', nargs='*', default=None, - help='Targets to build. Target has the following format: [PATH_TO_TARGET/]TARGET_NAME[:TARGET_TYPE].') + help='Targets to build. Target has the following format: [PATH_TO_TARGET/]TARGET_NAME.TARGET_SUFFIX[:TARGET_TYPE].') parser.add_argument( '--clean', action='store_true', diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 030b216d7786..f5048837f77a 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -2049,6 +2049,15 @@ def test_executable_names(self): self.assertPathExists(exe2) self.assertNotEqual(exe1, exe2) + # Wipe and run the compile command against the target names + self.init(testdir, extra_args=['--wipe']) + self._run([*self.meson_command, 'compile', '-C', self.builddir, './foo']) + self._run([*self.meson_command, 'compile', '-C', self.builddir, './foo.bin']) + self.assertPathExists(exe1) + self.assertPathExists(exe2) + self.assertNotEqual(exe1, exe2) + + def opt_has(self, name, value): res = self.introspect('--buildoptions') found = False