Merge pull request #8305 from xclaesse/run-target-env

run_target: Add env kwarg
pull/8083/head
Jussi Pakkanen 4 years ago committed by GitHub
commit 8b82ffa9e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      docs/markdown/Reference-manual.md
  2. 2
      docs/markdown/snippets/customtarget_env.md
  3. 45
      mesonbuild/backend/backends.py
  4. 79
      mesonbuild/backend/ninjabackend.py
  5. 38
      mesonbuild/backend/vs2010backend.py
  6. 72
      mesonbuild/build.py
  7. 7
      mesonbuild/interpreter.py
  8. 8
      mesonbuild/modules/gnome.py
  9. 6
      mesonbuild/modules/i18n.py
  10. 84
      mesonbuild/scripts/commandrunner.py
  11. 11
      mesonbuild/scripts/meson_exe.py
  12. 1
      run_unittests.py
  13. 9
      test cases/common/52 run target/check-env.py
  14. 6
      test cases/common/52 run target/meson.build

@ -1504,6 +1504,10 @@ and subdirectory the target was defined in, respectively.
- `depends` is a list of targets that this target depends on but which
are not listed in the command array (because, for example, the
script does file globbing internally)
- `env` *(since 0.57.0)*: environment variables to set, such as
`{'NAME1': 'value1', 'NAME2': 'value2'}` or `['NAME1=value1', 'NAME2=value2']`,
or an [`environment()` object](#environment-object) which allows more
sophisticated environment juggling.
### set_variable()

@ -1,4 +1,4 @@
## `custom_target()` now accepts an `env` keyword argument
## `custom_target()` and `run_target()` now accepts an `env` keyword argument
Environment variables can now be passed to the `custom_target()` command.

@ -21,8 +21,6 @@ import json
import os
import pickle
import re
import shlex
import textwrap
import typing as T
import hashlib
import copy
@ -34,7 +32,7 @@ from .. import mlog
from ..compilers import LANGUAGES_USING_LDFLAGS
from ..mesonlib import (
File, MachineChoice, MesonException, OptionType, OrderedSet, OptionOverrideProxy,
classify_unity_sources, unholder, OptionKey
classify_unity_sources, unholder, OptionKey, join_args
)
if T.TYPE_CHECKING:
@ -138,6 +136,7 @@ class ExecutableSerialisation:
self.capture = capture
self.pickled = False
self.skip_if_destdir = False
self.verbose = False
class TestSerialisation:
def __init__(self, name: str, project: str, suite: str, fname: T.List[str],
@ -432,12 +431,14 @@ class Backend:
def as_meson_exe_cmdline(self, tname, exe, cmd_args, workdir=None,
extra_bdeps=None, capture=None, force_serialize=False,
env: T.Optional[build.EnvironmentVariables] = None):
env: T.Optional[build.EnvironmentVariables] = None,
verbose: bool = False):
'''
Serialize an executable for running with a generator or a custom target
'''
cmd = [exe] + cmd_args
es = self.get_executable_serialisation(cmd, workdir, extra_bdeps, capture, env)
es.verbose = verbose
reasons = []
if es.extra_paths:
reasons.append('to set PATH')
@ -987,18 +988,8 @@ class Backend:
if delta > 0.001:
raise MesonException('Clock skew detected. File {} has a time stamp {:.4f}s in the future.'.format(absf, delta))
def build_target_to_cmd_array(self, bt, check_cross):
def build_target_to_cmd_array(self, bt):
if isinstance(bt, build.BuildTarget):
if check_cross and isinstance(bt, build.Executable) and bt.for_machine is not MachineChoice.BUILD:
if (self.environment.is_cross_build() and
self.environment.exe_wrapper is None and
self.environment.need_exe_wrapper()):
s = textwrap.dedent('''
Cannot use target {} as a generator because it is built for the
host machine and no exe wrapper is defined or needs_exe_wrapper is
true. You might want to set `native: true` instead to build it for
the build machine.'''.format(bt.name))
raise MesonException(s)
arr = [os.path.join(self.environment.get_build_dir(), self.get_target_filename(bt))]
else:
arr = bt.get_command()
@ -1129,11 +1120,9 @@ class Backend:
inputs = self.get_custom_target_sources(target)
# Evaluate the command list
cmd = []
index = -1
for i in target.command:
index += 1
if isinstance(i, build.BuildTarget):
cmd += self.build_target_to_cmd_array(i, (index == 0))
cmd += self.build_target_to_cmd_array(i)
continue
elif isinstance(i, build.CustomTarget):
# GIR scanner will attempt to execute this binary but
@ -1146,10 +1135,7 @@ class Backend:
i = os.path.join(self.environment.get_build_dir(), i)
# FIXME: str types are blindly added ignoring 'target.absolute_paths'
# because we can't know if they refer to a file or just a string
elif not isinstance(i, str):
err_msg = 'Argument {0} is of unknown type {1}'
raise RuntimeError(err_msg.format(str(i), str(type(i))))
else:
elif isinstance(i, str):
if '@SOURCE_ROOT@' in i:
i = i.replace('@SOURCE_ROOT@', source_root)
if '@BUILD_ROOT@' in i:
@ -1179,6 +1165,9 @@ class Backend:
else:
lead_dir = self.environment.get_build_dir()
i = i.replace(source, os.path.join(lead_dir, outdir))
else:
err_msg = 'Argument {0} is of unknown type {1}'
raise RuntimeError(err_msg.format(str(i), str(type(i))))
cmd.append(i)
# Substitute the rest of the template strings
values = mesonlib.get_filenames_templates_dict(inputs, outputs)
@ -1204,11 +1193,21 @@ class Backend:
cmd = [i.replace('\\', '/') for i in cmd]
return inputs, outputs, cmd
def get_run_target_env(self, target: build.RunTarget) -> build.EnvironmentVariables:
env = target.env if target.env else build.EnvironmentVariables()
introspect_cmd = join_args(self.environment.get_build_command() + ['introspect'])
env.add_var(env.set, 'MESON_SOURCE_ROOT', [self.environment.get_source_dir()], {})
env.add_var(env.set, 'MESON_BUILD_ROOT', [self.environment.get_build_dir()], {})
env.add_var(env.set, 'MESON_SUBDIR', [target.subdir], {})
env.add_var(env.set, 'MESONINTROSPECT', [introspect_cmd], {})
return env
def run_postconf_scripts(self) -> None:
from ..scripts.meson_exe import run_exe
introspect_cmd = join_args(self.environment.get_build_command() + ['introspect'])
env = {'MESON_SOURCE_ROOT': self.environment.get_source_dir(),
'MESON_BUILD_ROOT': self.environment.get_build_dir(),
'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in self.environment.get_build_command() + ['introspect']]),
'MESONINTROSPECT': introspect_cmd,
}
for s in self.build.postconf_scripts:

@ -28,7 +28,6 @@ from .. import modules
from .. import environment, mesonlib
from .. import build
from .. import mlog
from .. import dependencies
from .. import compilers
from ..arglist import CompilerArgs
from ..compilers import (
@ -974,7 +973,6 @@ int dummy;
elem.add_item('DEPFILE', rel_dfile)
if target.console:
elem.add_item('pool', 'console')
cmd = self.replace_paths(target, cmd)
elem.add_item('COMMAND', cmd)
elem.add_item('description', desc.format(target.name, cmd_type))
self.add_build(elem)
@ -988,65 +986,28 @@ int dummy;
return '{}{}'.format(subproject_prefix, target.name)
def generate_run_target(self, target):
cmd = self.environment.get_build_command() + ['--internal', 'commandrunner']
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)
arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname))
deps.append(relfname)
elif isinstance(i, mesonlib.File):
relfname = i.rel_to_builddir(self.build_to_src)
arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname))
else:
raise AssertionError('Unreachable code in generate_run_target: ' + str(i))
cmd += [self.environment.get_source_dir(),
self.environment.get_build_dir(),
target.subdir] + self.environment.get_build_command()
texe = target.command
try:
texe = texe.held_object
except AttributeError:
pass
if isinstance(texe, build.Executable):
abs_exe = os.path.join(self.environment.get_build_dir(), self.get_target_filename(texe))
deps.append(self.get_target_filename(texe))
if self.environment.is_cross_build():
exe_wrap = self.environment.get_exe_wrapper()
if exe_wrap:
if not exe_wrap.found():
msg = 'The exe_wrapper {!r} defined in the cross file is ' \
'needed by run target {!r}, but was not found. ' \
'Please check the command and/or add it to PATH.'
raise MesonException(msg.format(exe_wrap.name, target.name))
cmd += exe_wrap.get_command()
cmd.append(abs_exe)
elif isinstance(texe, dependencies.ExternalProgram):
cmd += texe.get_command()
elif isinstance(texe, build.CustomTarget):
deps.append(self.get_target_filename(texe))
cmd += [os.path.join(self.environment.get_build_dir(), self.get_target_filename(texe))]
elif isinstance(texe, mesonlib.File):
cmd.append(texe.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()))
target_name = self.build_run_target_name(target)
if not target.command:
# This is an alias target, it has no command, it just depends on
# other targets.
elem = NinjaBuildElement(self.all_outputs, target_name, 'phony', [])
else:
cmd.append(target.command)
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 {}'.format(target.name))
target_env = self.get_run_target_env(target)
_, _, cmd = self.eval_custom_target_command(target)
desc = 'Running external command {}{}'
meson_exe_cmd, reason = self.as_meson_exe_cmdline(target_name, cmd[0], cmd[1:],
force_serialize=True, env=target_env,
verbose=True)
cmd_type = ' (wrapped by meson {})'.format(reason)
internal_target_name = 'meson-{}'.format(target_name)
elem = NinjaBuildElement(self.all_outputs, internal_target_name, 'CUSTOM_COMMAND', [])
elem.add_item('COMMAND', meson_exe_cmd)
elem.add_item('description', desc.format(target.name, cmd_type))
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', [])
self.create_target_alias(internal_target_name)
deps = self.unwrap_dep_list(target)
deps += self.get_custom_target_depend_files(target)
elem.add_dep(deps)
self.add_build(elem)
self.processed_targets[target.get_id()] = True
@ -2105,7 +2066,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
generator = genlist.get_generator()
subdir = genlist.subdir
exe = generator.get_exe()
exe_arr = self.build_target_to_cmd_array(exe, True)
exe_arr = self.build_target_to_cmd_array(exe)
infilelist = genlist.get_inputs()
outfilelist = genlist.get_outputs()
extra_dependencies = self.get_custom_target_depend_files(genlist)

@ -28,7 +28,7 @@ from .. import mlog
from .. import compilers
from ..interpreter import Interpreter
from ..mesonlib import (
MesonException, File, python_command, replace_if_different, OptionKey,
MesonException, python_command, replace_if_different, OptionKey,
)
from ..environment import Environment, build_filename
@ -121,7 +121,7 @@ class Vs2010Backend(backends.Backend):
infilelist = genlist.get_inputs()
outfilelist = genlist.get_outputs()
source_dir = os.path.join(down, self.build_to_src, genlist.subdir)
exe_arr = self.build_target_to_cmd_array(exe, True)
exe_arr = self.build_target_to_cmd_array(exe)
idgroup = ET.SubElement(parent_node, 'ItemGroup')
for i in range(len(infilelist)):
if len(infilelist) == len(outfilelist):
@ -257,9 +257,8 @@ class Vs2010Backend(backends.Backend):
for d in target.get_target_dependencies():
all_deps[d.get_id()] = d
elif isinstance(target, build.RunTarget):
for d in [target.command] + target.args:
if isinstance(d, (build.BuildTarget, build.CustomTarget)):
all_deps[d.get_id()] = d
for d in target.get_dependencies():
all_deps[d.get_id()] = d
elif isinstance(target, build.BuildTarget):
for ldep in target.link_targets:
if isinstance(ldep, build.CustomTargetIndex):
@ -534,27 +533,14 @@ class Vs2010Backend(backends.Backend):
# 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 + \
[os.path.join(self.environment.get_script_dir(), 'commandrunner.py'),
self.environment.get_source_dir(),
self.environment.get_build_dir(),
self.get_target_dir(target)] + self.environment.get_build_command()
for i in cmd_raw:
if isinstance(i, build.BuildTarget):
cmd.append(os.path.join(self.environment.get_build_dir(), self.get_target_filename(i)))
elif isinstance(i, dependencies.ExternalProgram):
cmd += i.get_command()
elif isinstance(i, File):
relfname = i.rel_to_builddir(self.build_to_src)
cmd.append(os.path.join(self.environment.get_build_dir(), relfname))
elif isinstance(i, str):
# Escape embedded quotes, because we quote the entire argument below.
cmd.append(i.replace('"', '\\"'))
else:
cmd.append(i)
cmd_templ = '''"%s" ''' * len(cmd)
self.add_custom_build(root, 'run_target', cmd_templ % tuple(cmd))
_, _, cmd_raw = self.eval_custom_target_command(target)
depend_files = self.get_custom_target_depend_files(target)
target_env = self.get_run_target_env(target)
wrapper_cmd, _ = self.as_meson_exe_cmdline(target.name, cmd_raw[0], cmd_raw[1:],
force_serialize=True, env=target_env,
verbose=True)
self.add_custom_build(root, 'run_target', ' '.join(self.quote_arguments(wrapper_cmd)),
deps=depend_files)
ET.SubElement(root, 'Import', Project=r'$(VCTargetsPath)\Microsoft.Cpp.targets')
self.add_regen_dependency(root)
self.add_target_deps(root, target)

@ -29,7 +29,7 @@ from .mesonlib import (
File, MesonException, MachineChoice, PerMachine, OrderedSet, listify,
extract_as_list, typeslistify, stringlistify, classify_unity_sources,
get_filenames_templates_dict, substitute_values, has_path_sep, unholder,
OptionKey,
OptionKey
)
from .compilers import (
Compiler, is_object, clink_langs, sort_clink, lang_suffixes,
@ -2142,8 +2142,35 @@ class SharedModule(SharedLibrary):
def get_default_install_dir(self, environment):
return environment.get_shared_module_dir()
class CommandBase:
def flatten_command(self, cmd):
cmd = unholder(listify(cmd))
final_cmd = []
for c in cmd:
if isinstance(c, str):
final_cmd.append(c)
elif isinstance(c, File):
self.depend_files.append(c)
final_cmd.append(c)
elif isinstance(c, dependencies.ExternalProgram):
if not c.found():
raise InvalidArguments('Tried to use not-found external program in "command"')
path = c.get_path()
if os.path.isabs(path):
# Can only add a dependency on an external program which we
# know the absolute path of
self.depend_files.append(File.from_absolute_file(path))
final_cmd += c.get_command()
elif isinstance(c, (BuildTarget, CustomTarget)):
self.dependencies.append(c)
final_cmd.append(c)
elif isinstance(c, list):
final_cmd += self.flatten_command(c)
else:
raise InvalidArguments('Argument {!r} in "command" is invalid'.format(c))
return final_cmd
class CustomTarget(Target):
class CustomTarget(Target, CommandBase):
known_kwargs = set([
'input',
'output',
@ -2214,33 +2241,6 @@ class CustomTarget(Target):
bdeps.update(d.get_transitive_build_target_deps())
return bdeps
def flatten_command(self, cmd):
cmd = unholder(listify(cmd))
final_cmd = []
for c in cmd:
if isinstance(c, str):
final_cmd.append(c)
elif isinstance(c, File):
self.depend_files.append(c)
final_cmd.append(c)
elif isinstance(c, dependencies.ExternalProgram):
if not c.found():
raise InvalidArguments('Tried to use not-found external program in "command"')
path = c.get_path()
if os.path.isabs(path):
# Can only add a dependency on an external program which we
# know the absolute path of
self.depend_files.append(File.from_absolute_file(path))
final_cmd += c.get_command()
elif isinstance(c, (BuildTarget, CustomTarget)):
self.dependencies.append(c)
final_cmd.append(c)
elif isinstance(c, list):
final_cmd += self.flatten_command(c)
else:
raise InvalidArguments('Argument {!r} in "command" is invalid'.format(c))
return final_cmd
def process_kwargs(self, kwargs, backend):
self.process_kwargs_base(kwargs)
self.sources = unholder(extract_as_list(kwargs, 'input'))
@ -2422,18 +2422,20 @@ class CustomTarget(Target):
for i in self.outputs:
yield CustomTargetIndex(self, i)
class RunTarget(Target):
def __init__(self, name, command, args, dependencies, subdir, subproject):
class RunTarget(Target, CommandBase):
def __init__(self, name, command, dependencies, subdir, subproject, env=None):
self.typename = 'run'
# These don't produce output artifacts
super().__init__(name, subdir, subproject, False, MachineChoice.BUILD)
self.command = command
self.args = args
self.dependencies = dependencies
self.depend_files = []
self.command = self.flatten_command(command)
self.absolute_paths = False
self.env = env
def __repr__(self):
repr_str = "<{0} {1}: {2}>"
return repr_str.format(self.__class__.__name__, self.get_id(), self.command)
return repr_str.format(self.__class__.__name__, self.get_id(), self.command[0])
def process_kwargs(self, kwargs):
return self.process_kwargs_base(kwargs)
@ -2466,7 +2468,7 @@ class RunTarget(Target):
class AliasTarget(RunTarget):
def __init__(self, name, dependencies, subdir, subproject):
super().__init__(name, '', [], dependencies, subdir, subproject)
super().__init__(name, [], dependencies, subdir, subproject)
class Jar(BuildTarget):
known_kwargs = known_jar_kwargs

@ -2378,7 +2378,7 @@ permitted_kwargs = {'add_global_arguments': {'language', 'native'},
'jar': build.known_jar_kwargs,
'project': {'version', 'meson_version', 'default_options', 'license', 'subproject_dir'},
'run_command': {'check', 'capture', 'env'},
'run_target': {'command', 'depends'},
'run_target': {'command', 'depends', 'env'},
'shared_library': build.known_shlib_kwargs,
'shared_module': build.known_shmod_kwargs,
'static_library': build.known_stlib_kwargs,
@ -4058,6 +4058,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
self.add_target(name, tg.held_object)
return tg
@FeatureNewKwargs('run_target', '0.57.0', ['env'])
@permittedKwargs(permitted_kwargs['run_target'])
def func_run_target(self, node, args, kwargs):
if len(args) > 1:
@ -4086,8 +4087,8 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
if not isinstance(d, (build.BuildTarget, build.CustomTarget)):
raise InterpreterException('Depends items must be build targets.')
cleaned_deps.append(d)
command, *cmd_args = cleaned_args
tg = RunTargetHolder(build.RunTarget(name, command, cmd_args, cleaned_deps, self.subdir, self.subproject), self)
env = self.unpack_env_kwarg(kwargs)
tg = RunTargetHolder(build.RunTarget(name, cleaned_args, cleaned_deps, self.subdir, self.subproject, env), self)
self.add_target(name, tg.held_object)
full_name = (self.subproject, name)
assert(full_name not in self.build.run_target_names)

@ -956,8 +956,8 @@ class GnomeModule(ExtensionModule):
'--id=' + project_id,
'--sources=' + source_str,
]
pottarget = build.RunTarget('help-' + project_id + '-pot', potargs[0],
potargs[1:], [], state.subdir, state.subproject)
pottarget = build.RunTarget('help-' + project_id + '-pot', potargs,
[], state.subdir, state.subproject)
poargs = state.environment.get_build_command() + [
'--internal', 'yelphelper', 'update-po',
@ -966,8 +966,8 @@ class GnomeModule(ExtensionModule):
'--sources=' + source_str,
'--langs=' + '@@'.join(langs),
]
potarget = build.RunTarget('help-' + project_id + '-update-po', poargs[0],
poargs[1:], [], state.subdir, state.subproject)
potarget = build.RunTarget('help-' + project_id + '-update-po', poargs,
[], state.subdir, state.subproject)
rv = [inscript, pottarget, potarget]
return ModuleReturnValue(None, rv)

@ -152,12 +152,12 @@ class I18nModule(ExtensionModule):
potargs.append(datadirs)
if extra_args:
potargs.append(extra_args)
pottarget = build.RunTarget(packagename + '-pot', potargs[0], potargs[1:], [], state.subdir, state.subproject)
pottarget = build.RunTarget(packagename + '-pot', potargs, [], state.subdir, state.subproject)
gmoargs = state.environment.get_build_command() + ['--internal', 'gettext', 'gen_gmo']
if lang_arg:
gmoargs.append(lang_arg)
gmotarget = build.RunTarget(packagename + '-gmo', gmoargs[0], gmoargs[1:], [], state.subdir, state.subproject)
gmotarget = build.RunTarget(packagename + '-gmo', gmoargs, [], state.subdir, state.subproject)
updatepoargs = state.environment.get_build_command() + ['--internal', 'gettext', 'update_po', pkg_arg]
if lang_arg:
@ -166,7 +166,7 @@ class I18nModule(ExtensionModule):
updatepoargs.append(datadirs)
if extra_args:
updatepoargs.append(extra_args)
updatepotarget = build.RunTarget(packagename + '-update-po', updatepoargs[0], updatepoargs[1:], [], state.subdir, state.subproject)
updatepotarget = build.RunTarget(packagename + '-update-po', updatepoargs, [], state.subdir, state.subproject)
targets = [pottarget, gmotarget, updatepotarget]

@ -1,84 +0,0 @@
# Copyright 2014 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This program is a wrapper to run external commands. It determines
what to run, sets up the environment and executes the command."""
import sys, os, subprocess, shutil, shlex
import re
import typing as T
def run_command(source_dir: str, build_dir: str, subdir: str, meson_command: T.List[str], command: str, arguments: T.List[str]) -> subprocess.Popen:
env = {'MESON_SOURCE_ROOT': source_dir,
'MESON_BUILD_ROOT': build_dir,
'MESON_SUBDIR': subdir,
'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in meson_command + ['introspect']]),
}
cwd = os.path.join(source_dir, subdir)
child_env = os.environ.copy()
child_env.update(env)
# Is the command an executable in path?
exe = shutil.which(command)
if exe is not None:
command_array = [exe] + arguments
else:# No? Maybe it is a script in the source tree.
fullpath = os.path.join(source_dir, subdir, command)
command_array = [fullpath] + arguments
try:
return subprocess.Popen(command_array, env=child_env, cwd=cwd)
except FileNotFoundError:
print('Could not execute command "%s". File not found.' % command)
sys.exit(1)
except PermissionError:
print('Could not execute command "%s". File not executable.' % command)
sys.exit(1)
except OSError as err:
print('Could not execute command "{}": {}'.format(command, err))
sys.exit(1)
except subprocess.SubprocessError as err:
print('Could not execute command "{}": {}'.format(command, err))
sys.exit(1)
def is_python_command(cmdname: str) -> bool:
end_py_regex = r'python(3|3\.\d+)?(\.exe)?$'
return re.search(end_py_regex, cmdname) is not None
def run(args: T.List[str]) -> int:
if len(args) < 4:
print('commandrunner.py <source dir> <build dir> <subdir> <command> [arguments]')
return 1
src_dir = args[0]
build_dir = args[1]
subdir = args[2]
meson_bin = args[3]
if is_python_command(meson_bin):
meson_command = [meson_bin, args[4]]
command = args[5]
arguments = args[6:]
else:
meson_command = [meson_bin]
command = args[4]
arguments = args[5:]
pc = run_command(src_dir, build_dir, subdir, meson_command, command, arguments)
while True:
try:
pc.wait()
break
except KeyboardInterrupt:
pass
return pc.returncode
if __name__ == '__main__':
sys.exit(run(sys.argv[1:]))

@ -52,10 +52,13 @@ def run_exe(exe: ExecutableSerialisation, extra_env: T.Optional[dict] = None) ->
['Z:' + p for p in exe.extra_paths] + child_env.get('WINEPATH', '').split(';')
)
pipe = subprocess.PIPE
if exe.verbose:
assert not exe.capture, 'Cannot capture and print to console at the same time'
pipe = None
p = subprocess.Popen(cmd_args, env=child_env, cwd=exe.workdir,
close_fds=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
close_fds=False, stdout=pipe, stderr=pipe)
stdout, stderr = p.communicate()
if p.returncode == 0xc0000135:
@ -65,6 +68,8 @@ def run_exe(exe: ExecutableSerialisation, extra_env: T.Optional[dict] = None) ->
if p.returncode != 0:
if exe.pickled:
print('while executing {!r}'.format(cmd_args))
if exe.verbose:
return p.returncode
if not exe.capture:
print('--- stdout ---')
print(stdout.decode())

@ -2381,6 +2381,7 @@ class AllPlatformTests(BasePlatformTests):
testdir = os.path.join(self.common_test_dir, '52 run target')
self.init(testdir)
self.run_target('check_exists')
self.run_target('check-env')
def test_install_introspection(self):
'''

@ -0,0 +1,9 @@
#!/usr/bin/env python3
import os
assert 'MESON_SOURCE_ROOT' in os.environ
assert 'MESON_BUILD_ROOT' in os.environ
assert 'MESON_SUBDIR' in os.environ
assert 'MESONINTROSPECT' in os.environ
assert 'MY_ENV' in os.environ

@ -72,3 +72,9 @@ run_target('ctags',
run_target('clang-format',
command : converter)
# Check we can pass env to the program
run_target('check-env',
command: [find_program('check-env.py')],
env: {'MY_ENV': '1'},
)

Loading…
Cancel
Save