aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.com>2021-02-20 12:04:01 -0500
committerXavier Claessens <xclaesse@gmail.com>2021-03-16 09:00:50 -0400
commit598e968993da58c89f773dc732c708a54b0ec8db (patch)
tree7aff62faa24d580ea64fdcf65922c7f0d109a712 /mesonbuild
parent567c96b68b1dfe3cd6b52b0d26dfc78e5c0e6b76 (diff)
downloadmeson-598e968993da58c89f773dc732c708a54b0ec8db.zip
meson-598e968993da58c89f773dc732c708a54b0ec8db.tar.gz
meson-598e968993da58c89f773dc732c708a54b0ec8db.tar.bz2
Add `meson devenv` command and meson.add_devenv()
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/backend/backends.py19
-rw-r--r--mesonbuild/build.py3
-rw-r--r--mesonbuild/interpreter.py19
-rw-r--r--mesonbuild/mdevenv.py79
-rw-r--r--mesonbuild/mesonmain.py4
-rw-r--r--mesonbuild/msetup.py1
-rw-r--r--mesonbuild/scripts/cmd_or_ps.ps122
7 files changed, 139 insertions, 8 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 9f7f45d..e2297a3 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -1491,3 +1491,22 @@ class Backend:
}]
return []
+
+ def get_devenv(self) -> build.EnvironmentVariables:
+ env = build.EnvironmentVariables()
+ extra_paths = set()
+ for t in self.build.get_targets().values():
+ cross_built = not self.environment.machines.matches_build_machine(t.for_machine)
+ can_run = not cross_built or not self.environment.need_exe_wrapper()
+ in_bindir = t.should_install() and not t.get_install_dir(self.environment)[1]
+ if isinstance(t, build.Executable) and can_run and in_bindir:
+ # Add binaries that are going to be installed in bindir into PATH
+ # so they get used by default instead of searching on system when
+ # in developer environment.
+ extra_paths.add(os.path.join(self.environment.get_build_dir(), self.get_target_dir(t)))
+ if mesonlib.is_windows() or mesonlib.is_cygwin():
+ # On windows we cannot rely on rpath to run executables from build
+ # directory. We have to add in PATH the location of every DLL needed.
+ extra_paths.update(self.determine_windows_extra_paths(t, []))
+ env.prepend('PATH', list(extra_paths))
+ return env
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index e3fad3d..b81e5dd 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -229,6 +229,7 @@ class Build:
self.find_overrides = {}
self.searched_programs = set() # The list of all programs that have been searched for.
self.dependency_overrides = PerMachine({}, {})
+ self.devenv: T.List[EnvironmentVariables] = []
def get_build_targets(self):
build_targets = OrderedDict()
@@ -393,7 +394,7 @@ class ExtractedObjects:
]
class EnvironmentVariables:
- def __init__(self):
+ def __init__(self) -> None:
self.envvars = []
# The set of all env vars we have operations for. Only used for self.has_name()
self.varnames = set()
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 84d5e5c..3e39720 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -32,7 +32,6 @@ from .interpreterbase import InterpreterObject, MutableInterpreterObject, Disabl
from .interpreterbase import FeatureNew, FeatureDeprecated, FeatureNewKwargs, FeatureDeprecatedKwargs
from .interpreterbase import ObjectHolder, MesonVersionString
from .interpreterbase import TYPE_var, TYPE_nkwargs
-from .interpreterbase import typed_pos_args
from .modules import ModuleReturnValue, ModuleObject, ModuleState
from .cmake import CMakeInterpreter
from .backend.backends import TestProtocol, Backend, ExecutableSerialisation
@@ -256,8 +255,8 @@ class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder[build.En
if isinstance(initial_values, dict):
for k, v in initial_values.items():
self.set_method([k, v], {})
- elif isinstance(initial_values, list):
- for e in initial_values:
+ elif initial_values is not None:
+ for e in mesonlib.stringlistify(initial_values):
if '=' not in e:
raise InterpreterException('Env var definition must be of type key=val.')
(k, val) = e.split('=', 1)
@@ -266,8 +265,6 @@ class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder[build.En
if ' ' in k:
raise InterpreterException('Env var key must not have spaces in it.')
self.set_method([k, val], {})
- elif initial_values:
- raise AssertionError('Unsupported EnvironmentVariablesHolder initial_values')
def __repr__(self) -> str:
repr_str = "<{0}: {1}>"
@@ -1915,6 +1912,7 @@ class MesonMain(InterpreterObject):
'get_external_property': self.get_external_property_method,
'has_external_property': self.has_external_property_method,
'backend': self.backend_method,
+ 'add_devenv': self.add_devenv_method,
})
def _find_source_script(self, prog: T.Union[str, mesonlib.File, ExecutableHolder], args):
@@ -2241,6 +2239,16 @@ class MesonMain(InterpreterObject):
for_machine = self.interpreter.machine_from_native_kwarg(kwargs)
return prop_name in self.interpreter.environment.properties[for_machine]
+ @FeatureNew('add_devenv', '0.58.0')
+ @noKwargs
+ @typed_pos_args('add_devenv', (str, list, dict, EnvironmentVariablesHolder))
+ def add_devenv_method(self, args: T.Union[str, list, dict, EnvironmentVariablesHolder], kwargs: T.Dict[str, T.Any]) -> None:
+ env = args[0]
+ if isinstance(env, (str, list, dict)):
+ env = EnvironmentVariablesHolder(env)
+ self.build.devenv.append(env.held_object)
+
+
known_library_kwargs = (
build.known_shlib_kwargs |
build.known_stlib_kwargs
@@ -4084,7 +4092,6 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
env = EnvironmentVariablesHolder(envlist)
env = env.held_object
else:
- envlist = listify(envlist)
# Convert from array to environment object
env = EnvironmentVariablesHolder(envlist)
env = env.held_object
diff --git a/mesonbuild/mdevenv.py b/mesonbuild/mdevenv.py
new file mode 100644
index 0000000..7594db2
--- /dev/null
+++ b/mesonbuild/mdevenv.py
@@ -0,0 +1,79 @@
+import os, subprocess
+import argparse
+import tempfile
+
+from pathlib import Path
+from . import build
+from .mesonlib import MesonException, is_windows
+
+import typing as T
+
+def add_arguments(parser: argparse.ArgumentParser) -> None:
+ parser.add_argument('-C', default='.', dest='wd',
+ help='directory to cd into before running')
+ parser.add_argument('command', nargs=argparse.REMAINDER,
+ help='Command to run in developer environment (default: interactive shell)')
+
+def get_windows_shell() -> str:
+ mesonbuild = Path(__file__).parent
+ script = mesonbuild / 'scripts' / 'cmd_or_ps.ps1'
+ command = ['powershell.exe', '-noprofile', '-executionpolicy', 'bypass', '-file', str(script)]
+ 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)
+
+ extra_env = build.EnvironmentVariables()
+ extra_env.set('MESON_DEVENV', ['1'])
+ extra_env.set('MESON_PROJECT_NAME', [b.project_name])
+
+ meson_uninstalled = Path(build_dir) / 'meson-uninstalled'
+ if meson_uninstalled.is_dir():
+ extra_env.prepend('PKG_CONFIG_PATH', [str(meson_uninstalled)])
+
+ return extra_env.get_env(env)
+
+def run(options: argparse.Namespace) -> int:
+ options.wd = os.path.abspath(options.wd)
+ buildfile = Path(options.wd) / 'meson-private' / 'build.dat'
+ 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)
+
+ devenv = get_env(b, options.wd)
+
+ args = options.command
+ if not args:
+ prompt_prefix = f'[{b.project_name}]'
+ if is_windows():
+ shell = get_windows_shell()
+ if shell == 'powershell.exe':
+ args = ['powershell.exe']
+ args += ['-NoLogo', '-NoExit']
+ prompt = f'function global:prompt {{ "{prompt_prefix} PS " + $PWD + "> "}}'
+ args += ['-Command', prompt]
+ else:
+ args = [os.environ.get("COMSPEC", r"C:\WINDOWS\system32\cmd.exe")]
+ args += ['/k', f'prompt {prompt_prefix} $P$G']
+ else:
+ args = [os.environ.get("SHELL", os.path.realpath("/bin/sh"))]
+ if "bash" in args[0] and not os.environ.get("MESON_DISABLE_PS1_OVERRIDE"):
+ tmprc = tempfile.NamedTemporaryFile(mode='w')
+ bashrc = os.path.expanduser('~/.bashrc')
+ if os.path.exists(bashrc):
+ tmprc.write(f'. {bashrc}\n')
+ tmprc.write(f'export PS1="{prompt_prefix} $PS1"')
+ tmprc.flush()
+ # Let the GC remove the tmp file
+ args.append("--rcfile")
+ args.append(tmprc.name)
+
+ try:
+ return subprocess.call(args, close_fds=False,
+ env=devenv,
+ cwd=options.wd)
+ except subprocess.CalledProcessError as e:
+ return e.returncode
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index 173e998..208cfe4 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -22,7 +22,7 @@ import shutil
from . import mesonlib
from . import mlog
-from . import mconf, mdist, minit, minstall, mintro, msetup, mtest, rewriter, msubprojects, munstable_coredata, mcompile
+from . import mconf, mdist, minit, minstall, mintro, msetup, mtest, rewriter, msubprojects, munstable_coredata, mcompile, mdevenv
from .mesonlib import MesonException
from .environment import detect_msys2_arch
from .wrap import wraptool
@@ -64,6 +64,8 @@ class CommandLineParser:
help_msg='Modify the project definition')
self.add_command('compile', mcompile.add_arguments, mcompile.run,
help_msg='Build the project')
+ self.add_command('devenv', mdevenv.add_arguments, mdevenv.run,
+ help_msg='Run commands in developer environment')
# Hidden commands
self.add_command('runpython', self.add_runpython_arguments, self.run_runpython_command,
diff --git a/mesonbuild/msetup.py b/mesonbuild/msetup.py
index f42d013..139b476 100644
--- a/mesonbuild/msetup.py
+++ b/mesonbuild/msetup.py
@@ -243,6 +243,7 @@ class MesonApp:
profile.runctx('intr.backend.generate()', globals(), locals(), filename=fname)
else:
intr.backend.generate()
+ b.devenv.append(intr.backend.get_devenv())
build.save(b, dumpfile)
if env.first_invocation:
coredata.write_cmd_line_file(self.build_dir, self.options)
diff --git a/mesonbuild/scripts/cmd_or_ps.ps1 b/mesonbuild/scripts/cmd_or_ps.ps1
new file mode 100644
index 0000000..ccef8e8
--- /dev/null
+++ b/mesonbuild/scripts/cmd_or_ps.ps1
@@ -0,0 +1,22 @@
+# Copyied from GStreamer project
+# Author: Seungha Yang <seungha.yang@navercorp.com>
+
+$i=1
+$ppid=(gwmi win32_process -Filter "processid='$pid'").parentprocessid
+$pname=(Get-Process -id $ppid).Name
+While($true) {
+ if($pname -eq "cmd" -Or $pname -eq "powershell") {
+ Write-Host ("{0}.exe" -f $pname)
+ Break
+ }
+
+ # 10 times iteration seems to be sufficient
+ if($i -gt 10) {
+ Break
+ }
+
+ # not found yet, find grand parant
+ $ppid=(gwmi win32_process -Filter "processid='$ppid'").parentprocessid
+ $pname=(Get-Process -id $ppid).Name
+ $i++
+}