aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/backend/backends.py4
-rw-r--r--mesonbuild/backend/ninjabackend.py16
-rw-r--r--mesonbuild/build.py5
-rw-r--r--mesonbuild/interpreter.py73
-rw-r--r--mesonbuild/modules/i18n.py4
-rw-r--r--test cases/common/58 run target/converter.py5
-rwxr-xr-xtest cases/common/58 run target/fakeburner.py13
-rw-r--r--test cases/common/58 run target/meson.build30
8 files changed, 117 insertions, 33 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index bc49966..05a3565 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -92,6 +92,7 @@ class Backend():
raise RuntimeError('No specified compiler can handle file ' + src)
def get_target_filename(self, target):
+ assert(isinstance(target, (build.BuildTarget, build.CustomTarget)))
targetdir = self.get_target_dir(target)
fname = target.get_filename()
if isinstance(fname, list):
@@ -101,6 +102,9 @@ class Backend():
filename = os.path.join(targetdir, fname)
return filename
+ def get_target_filename_abs(self, target):
+ return os.path.join(self.environment.get_build_dir(), self.get_target_filename(target))
+
def get_target_filename_for_linking(self, target):
# On some platforms (msvc for instance), the file that is used for
# dynamic linking is not the same as the dynamic library itself. This
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index b583e62..9bc4842 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -347,11 +347,8 @@ int dummy;
if isinstance(s, build.GeneratedList):
self.generate_genlist_for_target(s, target, outfile)
- def generate_custom_target(self, target, outfile):
- self.custom_target_generator_inputs(target, outfile)
- (srcs, ofilenames, cmd) = self.eval_custom_target_command(target)
+ def unwrap_dep_list(self, target):
deps = []
- desc = 'Generating {0} with a {1} command.'
for i in target.get_dependencies():
# FIXME, should not grab element at zero but rather expand all.
if isinstance(i, list):
@@ -360,6 +357,13 @@ int dummy;
if isinstance(fname, list):
fname = fname[0]
deps.append(os.path.join(self.get_target_dir(i), fname))
+ return deps
+
+ def generate_custom_target(self, target, outfile):
+ self.custom_target_generator_inputs(target, outfile)
+ (srcs, ofilenames, cmd) = self.eval_custom_target_command(target)
+ deps = self.unwrap_dep_list(target)
+ desc = 'Generating {0} with a {1} command.'
if target.build_always:
deps.append('PHONY')
elem = NinjaBuildElement(self.all_outputs, ofilenames, 'CUSTOM_COMMAND', srcs)
@@ -397,19 +401,19 @@ int dummy;
def generate_run_target(self, target, outfile):
runnerscript = [sys.executable, self.environment.get_build_command(), '--internal', 'commandrunner']
- deps = []
+ deps = self.unwrap_dep_list(target)
arg_strings = []
for i in target.args:
if isinstance(i, str):
arg_strings.append(i)
elif isinstance(i, (build.BuildTarget, build.CustomTarget)):
relfname = self.get_target_filename(i)
- deps.append(relfname)
arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname))
else:
mlog.debug(str(i))
raise MesonException('Unreachable code in generate_run_target.')
elem = NinjaBuildElement(self.all_outputs, target.name, 'CUSTOM_COMMAND', deps)
+ elem.add_dep(deps)
cmd = runnerscript + [self.environment.get_source_dir(), self.environment.get_build_dir(), target.subdir]
texe = target.command
try:
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index bfdbca8..c60f37f 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -937,10 +937,11 @@ class CustomTarget:
return "@cus"
class RunTarget:
- def __init__(self, name, command, args, subdir):
+ def __init__(self, name, command, args, dependencies, subdir):
self.name = name
self.command = command
self.args = args
+ self.dependencies = dependencies
self.subdir = subdir
def get_id(self):
@@ -950,7 +951,7 @@ class RunTarget:
return self.name
def get_dependencies(self):
- return []
+ return self.dependencies
def get_generated_sources(self):
return []
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index c997e0e..5281be5 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -23,11 +23,13 @@ from . import compilers
from .wrap import wrap
from . import mesonlib
-import os, sys, platform, subprocess, shutil, uuid, re
+import os, sys, subprocess, shutil, uuid, re
from functools import wraps
import importlib
+run_depr_printed = False
+
class InterpreterException(mesonlib.MesonException):
pass
@@ -473,6 +475,7 @@ class BuildTargetHolder(InterpreterObject):
'extract_all_objects' : self.extract_all_objects_method,
'get_id': self.get_id_method,
'outdir' : self.outdir_method,
+ 'full_path' : self.full_path_method,
'private_dir_include' : self.private_dir_include_method,
})
@@ -483,6 +486,9 @@ class BuildTargetHolder(InterpreterObject):
return IncludeDirsHolder(build.IncludeDirs('', [], False,
[self.interpreter.backend.get_target_private_dir(self.held_object)]))
+ def full_path_method(self, args, kwargs):
+ return self.interpreter.backend.get_target_filename_abs(self.held_object)
+
def outdir_method(self, args, kwargs):
return self.interpreter.backend.get_target_dir(self.held_object)
@@ -514,19 +520,19 @@ class JarHolder(BuildTargetHolder):
super().__init__(target, interp)
class CustomTargetHolder(InterpreterObject):
- def __init__(self, object_to_hold):
+ def __init__(self, object_to_hold, interp):
+ super().__init__()
self.held_object = object_to_hold
+ self.interpreter = interp
+ self.methods.update({'full_path' : self.full_path_method,
+ })
- def is_cross(self):
- return self.held_object.is_cross()
-
- def extract_objects_method(self, args, kwargs):
- gobjs = self.held_object.extract_objects(args)
- return GeneratedObjectsHolder(gobjs)
+ def full_path_method(self, args, kwargs):
+ return self.interpreter.backend.get_target_filename_abs(self.held_object)
class RunTargetHolder(InterpreterObject):
- def __init__(self, name, command, args, subdir):
- self.held_object = build.RunTarget(name, command, args, subdir)
+ def __init__(self, name, command, args, dependencies, subdir):
+ self.held_object = build.RunTarget(name, command, args, dependencies, subdir)
class Test(InterpreterObject):
def __init__(self, name, suite, exe, is_parallel, cmd_args, env, should_fail, valgrind_args, timeout, workdir):
@@ -1069,7 +1075,7 @@ class Interpreter():
for v in invalues:
if isinstance(v, build.CustomTarget):
self.add_target(v.name, v)
- outvalues.append(CustomTargetHolder(v))
+ outvalues.append(CustomTargetHolder(v, self))
elif isinstance(v, int) or isinstance(v, str):
outvalues.append(v)
elif isinstance(v, build.Executable):
@@ -1754,16 +1760,32 @@ class Interpreter():
if len(args) != 1:
raise InterpreterException('Incorrect number of arguments')
name = args[0]
- tg = CustomTargetHolder(build.CustomTarget(name, self.subdir, kwargs))
+ tg = CustomTargetHolder(build.CustomTarget(name, self.subdir, kwargs), self)
self.add_target(name, tg.held_object)
return tg
- @noKwargs
def func_run_target(self, node, args, kwargs):
- if len(args) < 2:
- raise InterpreterException('Incorrect number of arguments')
+ global run_depr_printed
+ if len(args) > 1:
+ if not run_depr_printed:
+ mlog.log(mlog.red('DEPRECATION'), 'positional version of run_target is deprecated, use the keyword version instead.')
+ run_depr_printed = True
+ if 'command' in kwargs:
+ raise InterpreterException('Can not have command both in positional and keyword arguments.')
+ all_args = args[1:]
+ deps = []
+ elif len(args) == 1:
+ if not 'command' in kwargs:
+ raise InterpreterException('Missing "command" keyword argument')
+ all_args = kwargs['command']
+ deps = kwargs.get('depends', [])
+ if not isinstance(deps, list):
+ deps = [deps]
+ else:
+ raise InterpreterException('Run_target needs at least one positional argument.')
+
cleaned_args = []
- for i in args:
+ for i in all_args:
try:
i = i.held_object
except AttributeError:
@@ -1772,10 +1794,21 @@ class Interpreter():
mlog.debug('Wrong type:', str(i))
raise InterpreterException('Invalid argument to run_target.')
cleaned_args.append(i)
- name = cleaned_args[0]
- command = cleaned_args[1]
- cmd_args = cleaned_args[2:]
- tg = RunTargetHolder(name, command, cmd_args, self.subdir)
+ name = args[0]
+ if not isinstance(name, str):
+ raise InterpreterException('First argument must be a string.')
+ cleaned_deps = []
+ for d in deps:
+ try:
+ d = d.held_object
+ except AttributeError:
+ pass
+ if not isinstance(d, (build.BuildTarget, build.CustomTarget)):
+ raise InterpreterException('Depends items must be build targets.')
+ cleaned_deps.append(d)
+ command = cleaned_args[0]
+ cmd_args = cleaned_args[1:]
+ tg = RunTargetHolder(name, command, cmd_args, cleaned_deps, self.subdir)
self.add_target(name, tg.held_object)
return tg
diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py
index 4b529c7..33874fa 100644
--- a/mesonbuild/modules/i18n.py
+++ b/mesonbuild/modules/i18n.py
@@ -26,9 +26,9 @@ class I18nModule:
raise coredata.MesonException('List of languages empty.')
extra_args = mesonlib.stringlistify(kwargs.get('args', []))
potargs = [state.environment.get_build_command(), '--internal', 'gettext', 'pot', packagename] + extra_args
- pottarget = build.RunTarget(packagename + '-pot', sys.executable, potargs, state.subdir)
+ pottarget = build.RunTarget(packagename + '-pot', sys.executable, potargs, [], state.subdir)
gmoargs = [state.environment.get_build_command(), '--internal', 'gettext', 'gen_gmo'] + languages
- gmotarget = build.RunTarget(packagename + '-gmo', sys.executable, gmoargs, state.subdir)
+ gmotarget = build.RunTarget(packagename + '-gmo', sys.executable, gmoargs, [], state.subdir)
installcmd = [sys.executable,
state.environment.get_build_command(),
'--internal',
diff --git a/test cases/common/58 run target/converter.py b/test cases/common/58 run target/converter.py
new file mode 100644
index 0000000..6acbc84
--- /dev/null
+++ b/test cases/common/58 run target/converter.py
@@ -0,0 +1,5 @@
+#!/usr/bin/env python3
+
+import sys
+
+open(sys.argv[2], 'wb').write(open(sys.argv[1], 'rb').read())
diff --git a/test cases/common/58 run target/fakeburner.py b/test cases/common/58 run target/fakeburner.py
new file mode 100755
index 0000000..a100a6f
--- /dev/null
+++ b/test cases/common/58 run target/fakeburner.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python3
+
+import sys
+
+plain_arg = sys.argv[1]
+_, filename, _ = plain_arg.split(':')
+try:
+ content = open(filename, 'rb').read()
+except FileNotFoundError:
+ print('Could not open file. Missing dependency?')
+ sys.exit(1)
+print('File opened, pretending to send it somewhere.')
+print(len(content), 'bytes uploaded')
diff --git a/test cases/common/58 run target/meson.build b/test cases/common/58 run target/meson.build
index fa25f2a..0febe35 100644
--- a/test cases/common/58 run target/meson.build
+++ b/test cases/common/58 run target/meson.build
@@ -1,12 +1,36 @@
project('run target', 'c')
-run_target('mycommand', 'scripts/script.sh')
+# deprecated format, fix once we remove support for it.
+run_target('mycommand','scripts/script.sh')
# Make it possible to run built programs.
# In cross builds exe_wrapper should be added if it exists.
exe = executable('helloprinter', 'helloprinter.c')
-run_target('runhello', exe, 'argument')
+run_target('runhello',
+ command : [exe, 'argument'])
+
+converter = find_program('converter.py')
+
+hex = custom_target('exe.hex',
+ input : exe,
+ output : 'exe.hex',
+ command : [converter, '@INPUT@', '@OUTPUT@',
+ ],
+)
+
+# These emulates the Arduino flasher application. It sandwiches the filename inside
+# a packed argument. Thus we need to declare it manually.
+run_target('upload',
+ command : ['fakeburner.py', 'x:@0@:y'.format(exe.full_path())],
+ depends : exe,
+)
+
+run_target('upload2',
+ command : ['fakeburner.py', 'x:@0@:y'.format(hex.full_path())],
+ depends : hex,
+)
python3 = find_program('python3')
-run_target('py3hi', python3, '-c', 'print("I am Python3.")')
+run_target('py3hi',
+ command : [python3, '-c', 'print("I am Python3.")'])