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.
pull/12340/head
Dudemanguy 1 year ago committed by Dylan Baker
parent adb1a360b9
commit 03a0d3ddfb
  1. 7
      docs/markdown/Commands.md
  2. 7
      docs/markdown/snippets/meson_compile_suffixes.md
  3. 40
      mesonbuild/mcompile.py
  4. 9
      unittests/allplatformstests.py

@ -58,14 +58,17 @@ Builds a default or a specified target of a configured Meson project.
*(since 0.55.0)* *(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', ...)`). - `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 `./`. - `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'. - `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`. used to uniquely identify the target in `meson.build`.
Note that `SUFFIX` did not exist prior to 1.3.0.
#### Backend specific arguments #### Backend specific arguments
*(since 0.55.0)* *(since 0.55.0)*

@ -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.

@ -61,9 +61,11 @@ def parse_introspect_data(builddir: Path) -> T.Dict[str, T.List[dict]]:
class ParsedTargetName: class ParsedTargetName:
full_name = '' full_name = ''
base_name = ''
name = '' name = ''
type = '' type = ''
path = '' path = ''
suffix = ''
def __init__(self, target: str): def __init__(self, target: str):
self.full_name = target self.full_name = target
@ -80,6 +82,13 @@ class ParsedTargetName:
else: else:
self.name = split[0] 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 @staticmethod
def _is_valid_type(type: str) -> bool: def _is_valid_type(type: str) -> bool:
# Amend docs in Commands.md when editing this list # Amend docs in Commands.md when editing this list
@ -96,19 +105,32 @@ class ParsedTargetName:
return type in allowed_types 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]: 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') raise MesonException(f'Can\'t invoke target `{target.full_name}`: target not found')
intro_targets = introspect_data[target.name] 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]] = [] found_targets: T.List[T.Dict[str, T.Any]] = []
resolved_bdir = builddir.resolve() 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 found_targets = intro_targets
else: else:
for intro_target in intro_targets: 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 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 (target.path and intro_target['filename'] != 'no_name' and
Path(target.path) != Path(intro_target['filename'][0]).relative_to(resolved_bdir).parent)): Path(target.path) != Path(intro_target['filename'][0]).relative_to(resolved_bdir).parent)):
continue continue
@ -119,12 +141,20 @@ def get_target_from_intro_data(target: ParsedTargetName, builddir: Path, introsp
elif len(found_targets) > 1: elif len(found_targets) > 1:
suggestions: T.List[str] = [] suggestions: T.List[str] = []
for i in found_targets: 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(' ', '_') t = i['type'].replace(' ', '_')
suggestions.append(f'- ./{p}:{t}') suggestions.append(f'- ./{p}:{t}')
suggestions_str = '\n'.join(suggestions) suggestions_str = '\n'.join(suggestions)
raise MesonException(f'Can\'t invoke target `{target.full_name}`: ambiguous name.' 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] return found_targets[0]
@ -278,7 +308,7 @@ def add_arguments(parser: 'argparse.ArgumentParser') -> None:
metavar='TARGET', metavar='TARGET',
nargs='*', nargs='*',
default=None, 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( parser.add_argument(
'--clean', '--clean',
action='store_true', action='store_true',

@ -2049,6 +2049,15 @@ class AllPlatformTests(BasePlatformTests):
self.assertPathExists(exe2) self.assertPathExists(exe2)
self.assertNotEqual(exe1, 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): def opt_has(self, name, value):
res = self.introspect('--buildoptions') res = self.introspect('--buildoptions')
found = False found = False

Loading…
Cancel
Save