diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 14802ebae..f62372864 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -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() diff --git a/docs/markdown/snippets/customtarget_env.md b/docs/markdown/snippets/customtarget_env.md index 69bfc0d8d..f2d651b78 100644 --- a/docs/markdown/snippets/customtarget_env.md +++ b/docs/markdown/snippets/customtarget_env.md @@ -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. diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index badc2d0ab..0ab506183 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -21,7 +21,6 @@ import json import os import pickle import re -import shlex import textwrap import typing as T import hashlib @@ -34,7 +33,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 +137,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], @@ -421,12 +421,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') @@ -1193,11 +1195,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: diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 36f1fd213..2bd22bf0f 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -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 ( @@ -989,65 +988,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 diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index c47fb4a10..f4e2bd033 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -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 @@ -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) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 36bce1c09..4abc80096 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -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 diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index c9b6e9a92..cf147c73d 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2377,7 +2377,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, @@ -4059,6 +4059,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: @@ -4087,8 +4088,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) diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index f564eb466..48b80e08a 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -907,8 +907,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', @@ -917,8 +917,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) diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py index ae24e6e32..54faf4cde 100644 --- a/mesonbuild/modules/i18n.py +++ b/mesonbuild/modules/i18n.py @@ -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] diff --git a/mesonbuild/scripts/commandrunner.py b/mesonbuild/scripts/commandrunner.py deleted file mode 100644 index aeeaa3bcf..000000000 --- a/mesonbuild/scripts/commandrunner.py +++ /dev/null @@ -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 [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:])) diff --git a/mesonbuild/scripts/meson_exe.py b/mesonbuild/scripts/meson_exe.py index 620f5792d..27db14423 100644 --- a/mesonbuild/scripts/meson_exe.py +++ b/mesonbuild/scripts/meson_exe.py @@ -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()) diff --git a/run_unittests.py b/run_unittests.py index da137532a..857ce6f2a 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -2192,6 +2192,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): ''' diff --git a/test cases/common/52 run target/check-env.py b/test cases/common/52 run target/check-env.py new file mode 100644 index 000000000..8df3e28c7 --- /dev/null +++ b/test cases/common/52 run target/check-env.py @@ -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 diff --git a/test cases/common/52 run target/meson.build b/test cases/common/52 run target/meson.build index 9abe69872..a28d21844 100644 --- a/test cases/common/52 run target/meson.build +++ b/test cases/common/52 run target/meson.build @@ -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'}, +)