aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2016-08-27 13:42:13 +0300
committerGitHub <noreply@github.com>2016-08-27 13:42:13 +0300
commit4e050c3d9b545a8c8e136d5c8e7eb9cee988fbc6 (patch)
treefd64a026c5c364ce296230ac40f68224318efbc7
parent3ed1ff1c714e35beb82d02a9f1a1bccb992329b2 (diff)
parentb7757189e4eb8a17182d07cdcad53e8f5ebad0ce (diff)
downloadmeson-4e050c3d9b545a8c8e136d5c8e7eb9cee988fbc6.zip
meson-4e050c3d9b545a8c8e136d5c8e7eb9cee988fbc6.tar.gz
meson-4e050c3d9b545a8c8e136d5c8e7eb9cee988fbc6.tar.bz2
Merge pull request #712 from QuLogic/capturing-custom-target
Allow capturing command output of a custom target.
-rw-r--r--authors.txt1
-rw-r--r--mesonbuild/backend/backends.py22
-rw-r--r--mesonbuild/backend/ninjabackend.py10
-rw-r--r--mesonbuild/build.py8
-rw-r--r--mesonbuild/scripts/meson_exe.py9
-rw-r--r--test cases/common/117 custom target capture/data_source.txt1
-rw-r--r--test cases/common/117 custom target capture/installed_files.txt1
-rw-r--r--test cases/common/117 custom target capture/meson.build16
-rwxr-xr-xtest cases/common/117 custom target capture/my_compiler.py13
9 files changed, 70 insertions, 11 deletions
diff --git a/authors.txt b/authors.txt
index e9fceb0..ddccebc 100644
--- a/authors.txt
+++ b/authors.txt
@@ -41,3 +41,4 @@ Vincent Szolnoky
Zhe Wang
Wim Taymans
Matthias Klumpp
+Elliott Sales de Andrade
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 806a6f3..fbc5079 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -37,7 +37,7 @@ class InstallData():
class ExecutableSerialisation():
def __init__(self, name, fname, cmd_args, env, is_cross, exe_wrapper,
- workdir, extra_paths):
+ workdir, extra_paths, capture):
self.name = name
self.fname = fname
self.cmd_args = cmd_args
@@ -46,6 +46,7 @@ class ExecutableSerialisation():
self.exe_runner = exe_wrapper
self.workdir = workdir
self.extra_paths = extra_paths
+ self.capture = capture
class TestSerialisation:
def __init__(self, name, suite, fname, is_cross, exe_wrapper, is_parallel, cmd_args, env,
@@ -176,18 +177,25 @@ class Backend():
raise MesonException('Unknown data type in object list.')
return obj_list
- def serialise_executable(self, exe, cmd_args, workdir, env={}):
+ def serialise_executable(self, exe, cmd_args, workdir, env={},
+ capture=None):
import uuid
# Can't just use exe.name here; it will likely be run more than once
- scratch_file = 'meson_exe_{0}_{1}.dat'.format(exe.name,
+ if isinstance(exe, (dependencies.ExternalProgram,
+ build.BuildTarget, build.CustomTarget)):
+ basename = exe.name
+ else:
+ basename = os.path.basename(exe)
+ scratch_file = 'meson_exe_{0}_{1}.dat'.format(basename,
str(uuid.uuid4())[:8])
exe_data = os.path.join(self.environment.get_scratch_dir(), scratch_file)
with open(exe_data, 'wb') as f:
if isinstance(exe, dependencies.ExternalProgram):
exe_fullpath = exe.fullpath
+ elif isinstance(exe, (build.BuildTarget, build.CustomTarget)):
+ exe_fullpath = [self.get_target_filename_abs(exe)]
else:
- exe_fullpath = [os.path.join(self.environment.get_build_dir(),
- self.get_target_filename(exe))]
+ exe_fullpath = [exe]
is_cross = self.environment.is_cross_build() and \
self.environment.cross_info.need_cross_compiler() and \
self.environment.cross_info.need_exe_wrapper()
@@ -199,9 +207,9 @@ class Backend():
extra_paths = self.determine_windows_extra_paths(exe)
else:
extra_paths = []
- es = ExecutableSerialisation(exe.name, exe_fullpath, cmd_args, env,
+ es = ExecutableSerialisation(basename, exe_fullpath, cmd_args, env,
is_cross, exe_wrapper, workdir,
- extra_paths)
+ extra_paths, capture)
pickle.dump(es, f)
return exe_data
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 15f298b..7855729 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -379,15 +379,19 @@ int dummy;
tmp = [tmp]
for fname in tmp:
elem.add_dep(os.path.join(self.get_target_dir(d), fname))
+ # If the target requires capturing stdout, then use the serialized
+ # executable wrapper to capture that output and save it to a file.
+ #
# Windows doesn't have -rpath, so for EXEs that need DLLs built within
# the project, we need to set PATH so the DLLs are found. We use
# a serialized executable wrapper for that and check if the
# CustomTarget command needs extra paths first.
- if mesonlib.is_windows() and \
- self.determine_windows_extra_paths(target.command[0]):
+ if target.capture or (mesonlib.is_windows() and
+ self.determine_windows_extra_paths(target.command[0])):
exe_data = self.serialise_executable(target.command[0], cmd[1:],
# All targets are built from the build dir
- self.environment.get_build_dir())
+ self.environment.get_build_dir(),
+ capture=ofilenames[0] if target.capture else None)
cmd = [sys.executable, self.environment.get_build_command(),
'--internal', 'exe', exe_data]
cmd_type = 'meson_exe.py custom'
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index dd03d81..ace4853 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -927,6 +927,7 @@ class CustomTarget:
known_kwargs = {'input' : True,
'output' : True,
'command' : True,
+ 'capture' : False,
'install' : True,
'install_dir' : True,
'build_always' : True,
@@ -982,6 +983,10 @@ class CustomTarget:
raise InvalidArguments('Output argument not a string.')
if '/' in i:
raise InvalidArguments('Output must not contain a path segment.')
+ self.capture = kwargs.get('capture', False)
+ if self.capture and len(self.output) != 1:
+ raise InvalidArguments(
+ 'Capturing can only output to a single file.')
if 'command' not in kwargs:
raise InvalidArguments('Missing keyword argument "command".')
cmd = kwargs['command']
@@ -1010,6 +1015,9 @@ class CustomTarget:
else:
raise InvalidArguments('Argument %s in "command" is invalid.' % i)
self.command = final_cmd
+ if self.capture and '@OUTPUT@' in self.command:
+ raise InvalidArguments(
+ '@OUTPUT@ is not allowed when capturing output.')
if 'install' in kwargs:
self.install = kwargs['install']
if not isinstance(self.install, bool):
diff --git a/mesonbuild/scripts/meson_exe.py b/mesonbuild/scripts/meson_exe.py
index f075fa0..1a0fcda 100644
--- a/mesonbuild/scripts/meson_exe.py
+++ b/mesonbuild/scripts/meson_exe.py
@@ -59,6 +59,13 @@ def run_exe(exe):
stderr=subprocess.PIPE,
env=child_env,
cwd=exe.workdir)
+ stdout, stderr = p.communicate()
+ if exe.capture and p.returncode == 0:
+ with open(exe.capture, 'wb') as output:
+ output.write(stdout)
+ if stderr:
+ sys.stderr.buffer.write(stderr)
+ return p.returncode
def run(args):
global options
@@ -68,7 +75,7 @@ def run(args):
print(sys.argv[0] + ' [data file]')
exe_data_file = options.args[0]
exe = pickle.load(open(exe_data_file, 'rb'))
- run_exe(exe)
+ return run_exe(exe)
if __name__ == '__main__':
sys.exit(run(sys.argv[1:]))
diff --git a/test cases/common/117 custom target capture/data_source.txt b/test cases/common/117 custom target capture/data_source.txt
new file mode 100644
index 0000000..0c23cc0
--- /dev/null
+++ b/test cases/common/117 custom target capture/data_source.txt
@@ -0,0 +1 @@
+This is a text only input file.
diff --git a/test cases/common/117 custom target capture/installed_files.txt b/test cases/common/117 custom target capture/installed_files.txt
new file mode 100644
index 0000000..d90a6b0
--- /dev/null
+++ b/test cases/common/117 custom target capture/installed_files.txt
@@ -0,0 +1 @@
+usr/subdir/data.dat
diff --git a/test cases/common/117 custom target capture/meson.build b/test cases/common/117 custom target capture/meson.build
new file mode 100644
index 0000000..6c19752
--- /dev/null
+++ b/test cases/common/117 custom target capture/meson.build
@@ -0,0 +1,16 @@
+project('custom target', 'c')
+
+python = find_program('python3')
+
+# Note that this will not add a dependency to the compiler executable.
+# Code will not be rebuilt if it changes.
+comp = '@0@/@1@'.format(meson.current_source_dir(), 'my_compiler.py')
+
+mytarget = custom_target('bindat',
+output : 'data.dat',
+input : 'data_source.txt',
+capture : true,
+command : [python, comp, '@INPUT@'],
+install : true,
+install_dir : 'subdir'
+)
diff --git a/test cases/common/117 custom target capture/my_compiler.py b/test cases/common/117 custom target capture/my_compiler.py
new file mode 100755
index 0000000..3e9ec23
--- /dev/null
+++ b/test cases/common/117 custom target capture/my_compiler.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python3
+
+import sys
+
+if __name__ == '__main__':
+ if len(sys.argv) != 2:
+ print(sys.argv[0], 'input_file')
+ sys.exit(1)
+ ifile = open(sys.argv[1]).read()
+ if ifile != 'This is a text only input file.\n':
+ print('Malformed input')
+ sys.exit(1)
+ print('This is a binary output file.')