Merge pull request #7762 from jon-turney/meson-exe-output-improve

Improve the output for meson wrapped commands
pull/7806/head
Jussi Pakkanen 4 years ago committed by GitHub
commit 400ec2d685
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 31
      mesonbuild/backend/backends.py
  2. 27
      mesonbuild/backend/ninjabackend.py
  3. 14
      mesonbuild/backend/vs2010backend.py
  4. 6
      mesonbuild/scripts/meson_exe.py
  5. 7
      test cases/failing build/5 failed pickled/meson.build

@ -114,6 +114,7 @@ class ExecutableSerialisation:
self.workdir = workdir self.workdir = workdir
self.extra_paths = extra_paths self.extra_paths = extra_paths
self.capture = capture self.capture = capture
self.pickled = False
class TestSerialisation: class TestSerialisation:
def __init__(self, name: str, project: str, suite: str, fname: T.List[str], def __init__(self, name: str, project: str, suite: str, fname: T.List[str],
@ -395,13 +396,30 @@ class Backend:
exe_cmd = ['mono'] + exe_cmd exe_cmd = ['mono'] + exe_cmd
exe_wrapper = None exe_wrapper = None
force_serialize = force_serialize or extra_paths or workdir or \ reasons = []
exe_wrapper or any('\n' in c for c in cmd_args) if extra_paths:
reasons.append('to set PATH')
if exe_wrapper:
reasons.append('to use exe_wrapper')
if workdir:
reasons.append('to set workdir')
if any('\n' in c for c in cmd_args):
reasons.append('because command contains newlines')
force_serialize = force_serialize or bool(reasons)
if capture:
reasons.append('to capture output')
if not force_serialize: if not force_serialize:
if not capture: if not capture:
return None return None, ''
return (self.environment.get_build_command() + return ((self.environment.get_build_command() +
['--internal', 'exe', '--capture', capture, '--'] + exe_cmd + cmd_args) ['--internal', 'exe', '--capture', capture, '--'] + exe_cmd + cmd_args),
', '.join(reasons))
workdir = workdir or self.environment.get_build_dir() workdir = workdir or self.environment.get_build_dir()
env = {} env = {}
@ -425,7 +443,8 @@ class Backend:
exe_wrapper, workdir, exe_wrapper, workdir,
extra_paths, capture) extra_paths, capture)
pickle.dump(es, f) pickle.dump(es, f)
return self.environment.get_build_command() + ['--internal', 'exe', '--unpickle', exe_data] return (self.environment.get_build_command() + ['--internal', 'exe', '--unpickle', exe_data],
', '.join(reasons))
def serialize_tests(self): def serialize_tests(self):
test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat') test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat')

@ -870,7 +870,7 @@ int dummy;
(srcs, ofilenames, cmd) = self.eval_custom_target_command(target) (srcs, ofilenames, cmd) = self.eval_custom_target_command(target)
deps = self.unwrap_dep_list(target) deps = self.unwrap_dep_list(target)
deps += self.get_custom_target_depend_files(target) deps += self.get_custom_target_depend_files(target)
desc = 'Generating {0} with a {1} command' desc = 'Generating {0} with a custom command{1}'
if target.build_always_stale: if target.build_always_stale:
deps.append('PHONY') deps.append('PHONY')
if target.depfile is None: if target.depfile is None:
@ -884,14 +884,14 @@ int dummy;
for output in d.get_outputs(): for output in d.get_outputs():
elem.add_dep(os.path.join(self.get_target_dir(d), output)) elem.add_dep(os.path.join(self.get_target_dir(d), output))
meson_exe_cmd = self.as_meson_exe_cmdline(target.name, target.command[0], cmd[1:], meson_exe_cmd, reason = self.as_meson_exe_cmdline(target.name, target.command[0], cmd[1:],
extra_bdeps=target.get_transitive_build_target_deps(), extra_bdeps=target.get_transitive_build_target_deps(),
capture=ofilenames[0] if target.capture else None) capture=ofilenames[0] if target.capture else None)
if meson_exe_cmd: if meson_exe_cmd:
cmd = meson_exe_cmd cmd = meson_exe_cmd
cmd_type = 'meson_exe.py custom' cmd_type = ' (wrapped by meson {})'.format(reason)
else: else:
cmd_type = 'custom' cmd_type = ''
if target.depfile is not None: if target.depfile is not None:
depfile = target.get_dep_outname(elem.infilenames) depfile = target.get_dep_outname(elem.infilenames)
rel_dfile = os.path.join(self.get_target_dir(target), depfile) rel_dfile = os.path.join(self.get_target_dir(target), depfile)
@ -2012,9 +2012,9 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
outfilelist = outfilelist[len(generator.outputs):] outfilelist = outfilelist[len(generator.outputs):]
args = self.replace_paths(target, args, override_subdir=subdir) args = self.replace_paths(target, args, override_subdir=subdir)
cmdlist = exe_arr + self.replace_extra_args(args, genlist) cmdlist = exe_arr + self.replace_extra_args(args, genlist)
meson_exe_cmd = self.as_meson_exe_cmdline('generator ' + cmdlist[0], meson_exe_cmd, reason = self.as_meson_exe_cmdline('generator ' + cmdlist[0],
cmdlist[0], cmdlist[1:], cmdlist[0], cmdlist[1:],
capture=outfiles[0] if generator.capture else None) capture=outfiles[0] if generator.capture else None)
if meson_exe_cmd: if meson_exe_cmd:
cmdlist = meson_exe_cmd cmdlist = meson_exe_cmd
abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target)) abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target))
@ -2026,11 +2026,16 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
elem.add_item('DEPFILE', depfile) elem.add_item('DEPFILE', depfile)
if len(extra_dependencies) > 0: if len(extra_dependencies) > 0:
elem.add_dep(extra_dependencies) elem.add_dep(extra_dependencies)
if len(generator.outputs) == 1: if len(generator.outputs) == 1:
elem.add_item('DESC', 'Generating {!r}.'.format(sole_output)) what = '{!r}'.format(sole_output)
else: else:
# since there are multiple outputs, we log the source that caused the rebuild # since there are multiple outputs, we log the source that caused the rebuild
elem.add_item('DESC', 'Generating source from {!r}.'.format(sole_output)) what = 'from {!r}.'.format(sole_output)
if reason:
reason = ' (wrapped by meson {})'.format(reason)
elem.add_item('DESC', 'Generating {}{}.'.format(what, reason))
if isinstance(exe, build.BuildTarget): if isinstance(exe, build.BuildTarget):
elem.add_dep(self.get_target_filename(exe)) elem.add_dep(self.get_target_filename(exe))
elem.add_item('COMMAND', cmdlist) elem.add_item('COMMAND', cmdlist)

@ -150,7 +150,7 @@ class Vs2010Backend(backends.Backend):
# Always use a wrapper because MSBuild eats random characters when # Always use a wrapper because MSBuild eats random characters when
# there are many arguments. # there are many arguments.
tdir_abs = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target)) tdir_abs = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target))
cmd = self.as_meson_exe_cmdline( cmd, _ = self.as_meson_exe_cmdline(
'generator ' + cmd[0], 'generator ' + cmd[0],
cmd[0], cmd[0],
cmd[1:], cmd[1:],
@ -567,12 +567,12 @@ class Vs2010Backend(backends.Backend):
# there are many arguments. # there are many arguments.
tdir_abs = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target)) tdir_abs = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target))
extra_bdeps = target.get_transitive_build_target_deps() extra_bdeps = target.get_transitive_build_target_deps()
wrapper_cmd = self.as_meson_exe_cmdline(target.name, target.command[0], cmd[1:], wrapper_cmd, _ = self.as_meson_exe_cmdline(target.name, target.command[0], cmd[1:],
# All targets run from the target dir # All targets run from the target dir
workdir=tdir_abs, workdir=tdir_abs,
extra_bdeps=extra_bdeps, extra_bdeps=extra_bdeps,
capture=ofilenames[0] if target.capture else None, capture=ofilenames[0] if target.capture else None,
force_serialize=True) force_serialize=True)
if target.build_always_stale: if target.build_always_stale:
# Use a nonexistent file to always consider the target out-of-date. # Use a nonexistent file to always consider the target out-of-date.
ofilenames += [self.nonexistent_file(os.path.join(self.environment.get_scratch_dir(), ofilenames += [self.nonexistent_file(os.path.join(self.environment.get_scratch_dir(),

@ -55,9 +55,12 @@ def run_exe(exe: ExecutableSerialisation) -> int:
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
stdout, stderr = p.communicate() stdout, stderr = p.communicate()
if exe.pickled and p.returncode != 0:
print('while executing {!r}'.format(cmd_args))
if p.returncode == 0xc0000135: if p.returncode == 0xc0000135:
# STATUS_DLL_NOT_FOUND on Windows indicating a common problem that is otherwise hard to diagnose # STATUS_DLL_NOT_FOUND on Windows indicating a common problem that is otherwise hard to diagnose
raise FileNotFoundError('Missing DLLs on calling {!r}'.format(cmd_args)) raise FileNotFoundError('due to missing DLLs')
if exe.capture and p.returncode == 0: if exe.capture and p.returncode == 0:
skip_write = False skip_write = False
@ -90,6 +93,7 @@ def run(args: T.List[str]) -> int:
parser.error('no other arguments can be used with --unpickle') parser.error('no other arguments can be used with --unpickle')
with open(options.unpickle, 'rb') as f: with open(options.unpickle, 'rb') as f:
exe = pickle.load(f) exe = pickle.load(f)
exe.pickled = True
else: else:
exe = ExecutableSerialisation(cmd_args, capture=options.capture) exe = ExecutableSerialisation(cmd_args, capture=options.capture)

@ -0,0 +1,7 @@
project('failed pickled command')
custom_target('failure',
command: ['false', '\n'],
output: 'output.txt',
build_by_default: true,
)
Loading…
Cancel
Save