Add alias_target() function

pull/5606/head
Xavier Claessens 5 years ago
parent 716140ddb4
commit 12d4031f52
  1. 1
      data/syntax-highlighting/vim/syntax/meson.vim
  2. 14
      docs/markdown/Reference-manual.md
  3. 12
      docs/markdown/snippets/alias_target.md
  4. 1
      mesonbuild/ast/interpreter.py
  5. 30
      mesonbuild/backend/ninjabackend.py
  6. 7
      mesonbuild/backend/vs2010backend.py
  7. 4
      mesonbuild/build.py
  8. 26
      mesonbuild/interpreter.py
  9. 13
      run_unittests.py
  10. 3
      test cases/unit/62 alias target/main.c
  11. 15
      test cases/unit/62 alias target/meson.build

@ -69,6 +69,7 @@ syn keyword mesonBuiltin
\ add_project_arguments \ add_project_arguments
\ add_project_link_arguments \ add_project_link_arguments
\ add_test_setup \ add_test_setup
\ alias_target
\ assert \ assert
\ benchmark \ benchmark
\ both_libraries \ both_libraries

@ -119,6 +119,20 @@ Note that all these options are also available while running the
`meson test` script for running tests instead of `ninja test` or `meson test` script for running tests instead of `ninja test` or
`msbuild RUN_TESTS.vcxproj`, etc depending on the backend. `msbuild RUN_TESTS.vcxproj`, etc depending on the backend.
### alias_target
``` meson
runtarget alias_target(target_name, dep1, ...)
```
Since *0.52.0*
This function creates a new top-level target. Like all top-level targets, this
integrates with the selected backend. For instance, with Ninja you can
run it as `ninja target_name`. This is a dummy target that does not execute any
command, but ensures that all dependencies are built. Dependencies can be any
build target (e.g. return value of executable(), custom_target(), etc)
### assert() ### assert()
``` meson ``` meson

@ -0,0 +1,12 @@
## alias_target
``` meson
runtarget alias_target(target_name, dep1, ...)
```
This function creates a new top-level target. Like all top-level targets, this
integrates with the selected backend. For instance, with Ninja you can
run it as `ninja target_name`. This is a dummy target that does not execute any
command, but ensures that all dependencies are built. Dependencies can be any
build target (e.g. return value of executable(), custom_target(), etc)

@ -117,6 +117,7 @@ class AstInterpreter(interpreterbase.InterpreterBase):
'add_test_setup': self.func_do_nothing, 'add_test_setup': self.func_do_nothing,
'find_library': self.func_do_nothing, 'find_library': self.func_do_nothing,
'subdir_done': self.func_do_nothing, 'subdir_done': self.func_do_nothing,
'alias_target': self.func_do_nothing,
}) })
def func_do_nothing(self, node, args, kwargs): def func_do_nothing(self, node, args, kwargs):

@ -702,6 +702,13 @@ int dummy;
self.add_build(elem) self.add_build(elem)
self.processed_targets[target.get_id()] = True self.processed_targets[target.get_id()] = True
def build_run_target_name(self, target):
if target.subproject != '':
subproject_prefix = '{}@@'.format(target.subproject)
else:
subproject_prefix = ''
return '{}{}'.format(subproject_prefix, target.name)
def generate_run_target(self, target): def generate_run_target(self, target):
cmd = self.environment.get_build_command() + ['--internal', 'commandrunner'] cmd = self.environment.get_build_command() + ['--internal', 'commandrunner']
deps = self.unwrap_dep_list(target) deps = self.unwrap_dep_list(target)
@ -718,12 +725,6 @@ int dummy;
arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname)) arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname))
else: else:
raise AssertionError('Unreachable code in generate_run_target: ' + str(i)) raise AssertionError('Unreachable code in generate_run_target: ' + str(i))
if target.subproject != '':
subproject_prefix = '{}@@'.format(target.subproject)
else:
subproject_prefix = ''
target_name = 'meson-{}{}'.format(subproject_prefix, target.name)
elem = NinjaBuildElement(self.all_outputs, target_name, 'CUSTOM_COMMAND', [])
cmd += [self.environment.get_source_dir(), cmd += [self.environment.get_source_dir(),
self.environment.get_build_dir(), self.environment.get_build_dir(),
target.subdir] + self.environment.get_build_command() target.subdir] + self.environment.get_build_command()
@ -756,14 +757,21 @@ int dummy;
cmd.append(target.command) cmd.append(target.command)
cmd += arg_strings cmd += arg_strings
if texe:
target_name = 'meson-{}'.format(self.build_run_target_name(target))
elem = NinjaBuildElement(self.all_outputs, target_name, 'CUSTOM_COMMAND', [])
elem.add_item('COMMAND', cmd)
elem.add_item('description', 'Running external command %s.' % target.name)
elem.add_item('pool', 'console')
# Alias that runs the target defined above with the name the user specified
self.create_target_alias(target_name)
else:
target_name = self.build_run_target_name(target)
elem = NinjaBuildElement(self.all_outputs, target_name, 'phony', [])
elem.add_dep(deps) elem.add_dep(deps)
cmd = self.replace_paths(target, cmd) cmd = self.replace_paths(target, cmd)
elem.add_item('COMMAND', cmd)
elem.add_item('description', 'Running external command %s.' % target.name)
elem.add_item('pool', 'console')
self.add_build(elem) self.add_build(elem)
# Alias that runs the target defined above with the name the user specified
self.create_target_alias(target_name)
self.processed_targets[target.get_id()] = True self.processed_targets[target.get_id()] = True
def generate_coverage_command(self, elem, outputs): def generate_coverage_command(self, elem, outputs):

@ -516,7 +516,12 @@ class Vs2010Backend(backends.Backend):
def gen_run_target_vcxproj(self, target, ofname, guid): def gen_run_target_vcxproj(self, target, ofname, guid):
root = self.create_basic_crap(target, guid) root = self.create_basic_crap(target, guid)
cmd_raw = [target.command] + target.args if not target.command:
# FIXME: This is an alias target that doesn't run any command, there
# is probably a better way than running a this dummy command.
cmd_raw = python_command + ['-c', 'exit']
else:
cmd_raw = [target.command] + target.args
cmd = python_command + \ cmd = python_command + \
[os.path.join(self.environment.get_script_dir(), 'commandrunner.py'), [os.path.join(self.environment.get_script_dir(), 'commandrunner.py'),
self.environment.get_build_dir(), self.environment.get_build_dir(),

@ -2205,6 +2205,10 @@ class RunTarget(Target):
def type_suffix(self): def type_suffix(self):
return "@run" return "@run"
class AliasTarget(RunTarget):
def __init__(self, name, dependencies, subdir, subproject):
super().__init__(name, '', [], dependencies, subdir, subproject)
class Jar(BuildTarget): class Jar(BuildTarget):
known_kwargs = known_jar_kwargs known_kwargs = known_jar_kwargs

@ -863,10 +863,9 @@ class CustomTargetHolder(TargetHolder):
return IncludeDirsHolder(build.IncludeDirs('', [], False, return IncludeDirsHolder(build.IncludeDirs('', [], False,
[os.path.join('@BUILD_ROOT@', self.interpreter.backend.get_target_dir(self.held_object))])) [os.path.join('@BUILD_ROOT@', self.interpreter.backend.get_target_dir(self.held_object))]))
class RunTargetHolder(InterpreterObject, ObjectHolder): class RunTargetHolder(TargetHolder):
def __init__(self, name, command, args, dependencies, subdir, subproject): def __init__(self, target, interp):
InterpreterObject.__init__(self) super().__init__(target, interp)
ObjectHolder.__init__(self, build.RunTarget(name, command, args, dependencies, subdir, subproject))
def __repr__(self): def __repr__(self):
r = '<{} {}: {}>' r = '<{} {}: {}>'
@ -2103,6 +2102,7 @@ class Interpreter(InterpreterBase):
'add_project_link_arguments': self.func_add_project_link_arguments, 'add_project_link_arguments': self.func_add_project_link_arguments,
'add_test_setup': self.func_add_test_setup, 'add_test_setup': self.func_add_test_setup,
'add_languages': self.func_add_languages, 'add_languages': self.func_add_languages,
'alias_target': self.func_alias_target,
'assert': self.func_assert, 'assert': self.func_assert,
'benchmark': self.func_benchmark, 'benchmark': self.func_benchmark,
'build_target': self.func_build_target, 'build_target': self.func_build_target,
@ -3300,7 +3300,23 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
raise InterpreterException('Depends items must be build targets.') raise InterpreterException('Depends items must be build targets.')
cleaned_deps.append(d) cleaned_deps.append(d)
command, *cmd_args = cleaned_args command, *cmd_args = cleaned_args
tg = RunTargetHolder(name, command, cmd_args, cleaned_deps, self.subdir, self.subproject) tg = RunTargetHolder(build.RunTarget(name, command, cmd_args, cleaned_deps, self.subdir, self.subproject), self)
self.add_target(name, tg.held_object)
return tg
@FeatureNew('alias_target', '0.52.0')
@noKwargs
def func_alias_target(self, node, args, kwargs):
if len(args) < 2:
raise InvalidCode('alias_target takes at least 2 arguments.')
name = args[0]
if not isinstance(name, str):
raise InterpreterException('First argument must be a string.')
deps = listify(args[1:], unholder=True)
for d in deps:
if not isinstance(d, (build.BuildTarget, build.CustomTarget)):
raise InterpreterException('Depends items must be build targets.')
tg = RunTargetHolder(build.AliasTarget(name, deps, self.subdir, self.subproject), self)
self.add_target(name, tg.held_object) self.add_target(name, tg.held_object)
return tg return tg

@ -3747,6 +3747,19 @@ recommended as it is not supported on some platforms''')
testdir = os.path.join(self.unit_test_dir, '61 cmake parser') testdir = os.path.join(self.unit_test_dir, '61 cmake parser')
self.init(testdir, extra_args=['-Dcmake_prefix_path=' + os.path.join(testdir, 'prefix')]) self.init(testdir, extra_args=['-Dcmake_prefix_path=' + os.path.join(testdir, 'prefix')])
def test_alias_target(self):
if self.backend is Backend.vs:
# FIXME: This unit test is broken with vs backend, needs investigation
raise unittest.SkipTest('Skipping alias_target test with {} backend'.format(self.backend.name))
testdir = os.path.join(self.unit_test_dir, '62 alias target')
self.init(testdir)
self.build()
self.assertPathDoesNotExist(os.path.join(self.builddir, 'prog' + exe_suffix))
self.assertPathDoesNotExist(os.path.join(self.builddir, 'hello.txt'))
self.run_target('build-all')
self.assertPathExists(os.path.join(self.builddir, 'prog' + exe_suffix))
self.assertPathExists(os.path.join(self.builddir, 'hello.txt'))
class FailureTests(BasePlatformTests): class FailureTests(BasePlatformTests):
''' '''
Tests that test failure conditions. Build files here should be dynamically Tests that test failure conditions. Build files here should be dynamically

@ -0,0 +1,3 @@
int main(int argc, char *argv[]) {
return 0;
}

@ -0,0 +1,15 @@
project('alias target', 'c')
python3 = import('python').find_installation()
exe_target = executable('prog', 'main.c',
build_by_default : false)
custom_target = custom_target('custom-target',
output : 'hello.txt',
command : [python3, '-c', 'print("hello")'],
capture : true,
build_by_default : false
)
alias_target('build-all', [exe_target, custom_target])
Loading…
Cancel
Save