Allow capturing command output of a custom target.

For commands that always output to stdout and don't have a "-o" or
"--output" or some other similar option, this 'capture' setting allows
the build to capture the result and place it in the output file.
pull/712/head
Elliott Sales de Andrade 8 years ago
parent dcaf2d7b3d
commit 70d94a5550
  1. 8
      mesonbuild/backend/backends.py
  2. 10
      mesonbuild/backend/ninjabackend.py
  3. 5
      mesonbuild/build.py
  4. 7
      mesonbuild/scripts/meson_exe.py
  5. 1
      test cases/common/117 custom target capture/data_source.txt
  6. 1
      test cases/common/117 custom target capture/installed_files.txt
  7. 16
      test cases/common/117 custom target capture/meson.build
  8. 13
      test cases/common/117 custom target capture/my_compiler.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,7 +177,8 @@ 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
if isinstance(exe, (dependencies.ExternalProgram,
@ -207,7 +209,7 @@ class Backend():
extra_paths = []
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

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

@ -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']

@ -59,6 +59,11 @@ 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)
return p.returncode
def run(args):
global options
@ -68,7 +73,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:]))

@ -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'
)

@ -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.')
Loading…
Cancel
Save