Skip to content

Commit

Permalink
mcompile: add suffix as an additional parameter
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Dudemanguy authored and dcbaker committed Oct 5, 2023
1 parent adb1a36 commit 03a0d3d
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 7 deletions.
7 changes: 5 additions & 2 deletions docs/markdown/Commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)*
Expand Down
7 changes: 7 additions & 0 deletions docs/markdown/snippets/meson_compile_suffixes.md
Original file line number Diff line number Diff line change
@@ -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.
40 changes: 35 additions & 5 deletions mesonbuild/mcompile.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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]

Expand Down Expand Up @@ -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',
Expand Down
9 changes: 9 additions & 0 deletions unittests/allplatformstests.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 03a0d3d

Please sign in to comment.