diff --git a/docs/markdown/snippets/devenv.md b/docs/markdown/snippets/devenv.md index 1c401c13a..505f9710b 100644 --- a/docs/markdown/snippets/devenv.md +++ b/docs/markdown/snippets/devenv.md @@ -16,3 +16,8 @@ a library name that matches one being built, Meson adds the needed auto-load commands into `/.gdbinit` file. When running gdb from top build directory, that file is loaded by gdb automatically. +## Print modified environment variables with `meson devenv --dump` + +With `--dump` option, all envorinment variables that have been modified are +printed instead of starting an interactive shell. It can be used by shell +scripts that wish to setup their environment themself. diff --git a/mesonbuild/build.py b/mesonbuild/build.py index a6648d387..35e5e66ec 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -476,6 +476,9 @@ class EnvironmentVariables(HoldableObject): def has_name(self, name: str) -> bool: return name in self.varnames + def get_names(self) -> T.Set[str]: + return self.varnames + def set(self, name: str, values: T.List[str], separator: str = os.pathsep) -> None: self.varnames.add(name) self.envvars.append((self._set, name, values, separator)) diff --git a/mesonbuild/mdevenv.py b/mesonbuild/mdevenv.py index 0fc85950e..6268c1dbc 100644 --- a/mesonbuild/mdevenv.py +++ b/mesonbuild/mdevenv.py @@ -2,10 +2,11 @@ import os, subprocess import argparse import tempfile import shutil +import itertools from pathlib import Path from . import build, minstall, dependencies -from .mesonlib import MesonException, RealPathAction, is_windows, setup_vsenv, OptionKey +from .mesonlib import MesonException, RealPathAction, is_windows, setup_vsenv, OptionKey, quote_arg from . import mlog import typing as T @@ -14,7 +15,9 @@ if T.TYPE_CHECKING: def add_arguments(parser: argparse.ArgumentParser) -> None: parser.add_argument('-C', dest='wd', action=RealPathAction, - help='directory to cd into before running') + help='Directory to cd into before running') + parser.add_argument('--dump', action='store_true', + help='Only print required environment (Since 0.62.0)') parser.add_argument('command', nargs=argparse.REMAINDER, help='Command to run in developer environment (default: interactive shell)') @@ -25,11 +28,7 @@ def get_windows_shell() -> str: result = subprocess.check_output(command) return result.decode().strip() -def get_env(b: build.Build, build_dir: str) -> T.Dict[str, str]: - env = os.environ.copy() - for i in b.devenv: - env = i.get_env(env) - +def get_env(b: build.Build, build_dir: str) -> T.Tuple[T.Dict[str, str], T.Set[str]]: extra_env = build.EnvironmentVariables() extra_env.set('MESON_DEVENV', ['1']) extra_env.set('MESON_PROJECT_NAME', [b.project_name]) @@ -38,7 +37,13 @@ def get_env(b: build.Build, build_dir: str) -> T.Dict[str, str]: if meson_uninstalled.is_dir(): extra_env.prepend('PKG_CONFIG_PATH', [str(meson_uninstalled)]) - return extra_env.get_env(env) + env = os.environ.copy() + varnames = set() + for i in itertools.chain(b.devenv, {extra_env}): + env = i.get_env(env) + varnames |= i.get_names() + + return env, varnames def bash_completion_files(b: build.Build, install_data: 'InstallData') -> T.List[str]: result = [] @@ -108,12 +113,21 @@ def run(options: argparse.Namespace) -> int: if not buildfile.is_file(): raise MesonException(f'Directory {options.wd!r} does not seem to be a Meson build directory.') b = build.load(options.wd) - install_data = minstall.load_install_data(str(privatedir / 'install.dat')) - setup_vsenv(b.need_vsenv) - devenv = get_env(b, options.wd) + devenv, varnames = get_env(b, options.wd) + if options.dump: + if options.command: + raise MesonException('--dump option does not allow running other command.') + for name in varnames: + print(f'{name}={quote_arg(devenv[name])}') + print(f'export {name}') + return 0 + + install_data = minstall.load_install_data(str(privatedir / 'install.dat')) write_gdb_script(privatedir, install_data) + setup_vsenv(b.need_vsenv) + args = options.command if not args: prompt_prefix = f'[{b.project_name}]'