aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/dependencies.py30
-rw-r--r--mesonbuild/interpreter.py64
-rw-r--r--test cases/common/105 find program path/meson.build9
-rwxr-xr-x[-rw-r--r--]test cases/common/105 find program path/program.py0
4 files changed, 52 insertions, 51 deletions
diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py
index ef7be3a..37e2cbd 100644
--- a/mesonbuild/dependencies.py
+++ b/mesonbuild/dependencies.py
@@ -465,8 +465,9 @@ class ExternalProgram:
@staticmethod
def _shebang_to_cmd(script):
"""
- Windows does not understand shebangs, so we check if the file has a
- shebang and manually parse it to figure out the interpreter to use
+ Check if the file has a shebang and manually parse it to figure out
+ the interpreter to use. This is useful if the script is not executable
+ or if we're on Windows (which does not understand shebangs).
"""
try:
with open(script) as f:
@@ -504,15 +505,17 @@ class ExternalProgram:
if os.path.exists(trial):
if self._is_executable(trial):
return [trial]
+ # Now getting desperate. Maybe it is a script file that is
+ # a) not chmodded executable, or
+ # b) we are on windows so they can't be directly executed.
+ return self._shebang_to_cmd(trial)
else:
- for ext in self.windows_exts:
- trial_ext = '{}.{}'.format(trial, ext)
- if os.path.exists(trial_ext):
- return [trial_ext]
- return False
- # Now getting desperate. Maybe it is a script file that is a) not chmodded
- # executable or b) we are on windows so they can't be directly executed.
- return self._shebang_to_cmd(trial)
+ if mesonlib.is_windows():
+ for ext in self.windows_exts:
+ trial_ext = '{}.{}'.format(trial, ext)
+ if os.path.exists(trial_ext):
+ return [trial_ext]
+ return False
def _search(self, name, search_dir):
'''
@@ -525,7 +528,8 @@ class ExternalProgram:
# Do a standard search in PATH
command = shutil.which(name)
if not mesonlib.is_windows():
- # On UNIX-like platforms, the standard PATH search is enough
+ # On UNIX-like platforms, shutil.which() is enough to find
+ # all executables whether in PATH or with an absolute path
return [command]
# HERE BEGINS THE TERROR OF WINDOWS
if command:
@@ -567,9 +571,9 @@ class ExternalProgram:
return self.command[:]
def get_path(self):
- # Assume that the last element is the full path to the script
- # If it's not a script, this will be an array of length 1
if self.found():
+ # Assume that the last element is the full path to the script or
+ # binary being run
return self.command[-1]
return None
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 7eb1f26..80d482e 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -23,7 +23,7 @@ from . import compilers
from .wrap import wrap, WrapMode
from . import mesonlib
from .mesonlib import FileMode, Popen_safe, get_meson_script
-from .dependencies import InternalDependency, Dependency
+from .dependencies import InternalDependency, Dependency, ExternalProgram
from .interpreterbase import InterpreterBase
from .interpreterbase import check_stringlist, noPosargs, noKwargs, stringArgs
from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode
@@ -72,17 +72,19 @@ class TryRunResultHolder(InterpreterObject):
class RunProcess(InterpreterObject):
- def __init__(self, command_array, source_dir, build_dir, subdir, mesonintrospect, in_builddir=False):
+ def __init__(self, cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir=False):
super().__init__()
- pc, self.stdout, self.stderr = self.run_command(command_array, source_dir, build_dir, subdir, mesonintrospect, in_builddir)
+ if not isinstance(cmd, ExternalProgram):
+ raise AssertionError('BUG: RunProcess must be passed an ExternalProgram')
+ pc, self.stdout, self.stderr = self.run_command(cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir)
self.returncode = pc.returncode
self.methods.update({'returncode': self.returncode_method,
'stdout': self.stdout_method,
'stderr': self.stderr_method,
})
- def run_command(self, command_array, source_dir, build_dir, subdir, mesonintrospect, in_builddir):
- cmd_name = command_array[0]
+ def run_command(self, cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir):
+ command_array = cmd.get_command() + args
env = {'MESON_SOURCE_ROOT': source_dir,
'MESON_BUILD_ROOT': build_dir,
'MESON_SUBDIR': subdir,
@@ -97,18 +99,6 @@ class RunProcess(InterpreterObject):
try:
return Popen_safe(command_array, env=child_env, cwd=cwd)
except FileNotFoundError:
- pass
- # Was not a command, is a program in path?
- exe = shutil.which(cmd_name)
- if exe is not None:
- command_array = [exe] + command_array[1:]
- return Popen_safe(command_array, env=child_env, cwd=cwd)
- # No? Maybe it is a script in the source tree.
- fullpath = os.path.join(source_dir, subdir, cmd_name)
- command_array = [fullpath] + command_array[1:]
- try:
- return Popen_safe(command_array, env=child_env, cwd=cwd)
- except FileNotFoundError:
raise InterpreterException('Could not execute command "%s".' % cmd_name)
def returncode_method(self, args, kwargs):
@@ -250,7 +240,6 @@ class DependencyHolder(InterpreterObject):
def found_method(self, args, kwargs):
if self.held_object.type_name == 'internal':
return True
-
return self.held_object.found()
def version_method(self, args, kwargs):
@@ -1105,7 +1094,8 @@ class MesonMain(InterpreterObject):
if found.found():
self._found_source_scripts[key] = found
else:
- raise InterpreterException('Script {!r} not found'.format(name))
+ m = 'Script or command {!r} not found or not executable'
+ raise InterpreterException(m.format(name))
return build.RunScript(found.get_command(), args)
def add_install_script_method(self, args, kwargs):
@@ -1469,28 +1459,38 @@ class Interpreter(InterpreterBase):
raise InterpreterException('Not enough arguments')
cmd = args[0]
cargs = args[1:]
+ srcdir = self.environment.get_source_dir()
+ builddir = self.environment.get_build_dir()
+ m = 'must be a string, or the output of find_program(), files(), or ' \
+ 'configure_file(); not {!r}'
if isinstance(cmd, ExternalProgramHolder):
- cmd = cmd.get_command()
- elif isinstance(cmd, str):
- cmd = [cmd]
+ cmd = cmd.held_object
else:
- raise InterpreterException('First argument should be find_program() '
- 'or string, not {!r}'.format(cmd))
+ if isinstance(cmd, mesonlib.File):
+ cmd = cmd.absolute_path(srcdir, builddir)
+ elif not isinstance(cmd, str):
+ raise InterpreterException('First argument ' + m.format(cmd))
+ # Prefer scripts in the current source directory
+ search_dir = os.path.join(srcdir, self.subdir)
+ prog = ExternalProgram(cmd, silent=True, search_dir=search_dir)
+ if not prog.found():
+ raise InterpreterException('Program or command {!r} not found'
+ 'or not executable'.format(cmd))
+ cmd = prog
expanded_args = []
for a in mesonlib.flatten(cargs):
if isinstance(a, str):
expanded_args.append(a)
elif isinstance(a, mesonlib.File):
- if a.is_built:
- raise InterpreterException('Can not use generated files in run_command.')
- expanded_args.append(os.path.join(self.environment.get_source_dir(), str(a)))
+ expanded_args.append(a.absolute_path(srcdir, builddir))
+ elif isinstance(a, ExternalProgramHolder):
+ expanded_args.append(a.held_object.get_path())
else:
- raise InterpreterException('Run_command arguments must be strings or the output of files().')
- args = cmd + expanded_args
+ raise InterpreterException('Arguments ' + m.format(a))
in_builddir = kwargs.get('in_builddir', False)
if not isinstance(in_builddir, bool):
raise InterpreterException('in_builddir must be boolean.')
- return RunProcess(args, self.environment.source_dir, self.environment.build_dir, self.subdir,
+ return RunProcess(cmd, expanded_args, srcdir, builddir, self.subdir,
get_meson_script(self.environment, 'mesonintrospect'), in_builddir)
@stringArgs
@@ -1846,7 +1846,7 @@ class Interpreter(InterpreterBase):
if progobj.found():
return progobj
if required and not progobj.found():
- raise InvalidArguments('Program "%s" not found.' % exename)
+ raise InvalidArguments('Program "%s" not found or not executable' % exename)
return progobj
def func_find_library(self, node, args, kwargs):
@@ -2426,7 +2426,7 @@ different subdirectory.
exe_wrapper.append(i)
elif isinstance(i, dependencies.ExternalProgram):
if not i.found():
- raise InterpreterException('Tried to use non-found external executable.')
+ raise InterpreterException('Tried to use non-found executable.')
exe_wrapper += i.get_command()
else:
raise InterpreterException('Exe wrapper can only contain strings or external binaries.')
diff --git a/test cases/common/105 find program path/meson.build b/test cases/common/105 find program path/meson.build
index e1e6d2e..0a81249 100644
--- a/test cases/common/105 find program path/meson.build
+++ b/test cases/common/105 find program path/meson.build
@@ -1,9 +1,6 @@
project('find program', 'c')
-python = find_program('python3', required : false)
-if not python.found()
- python = find_program('python')
-endif
+python = import('python3').find_python()
# Source file via string
prog = find_program('program.py')
@@ -14,8 +11,8 @@ py = configure_file(input : 'program.py',
output : 'builtprogram.py',
configuration : configuration_data())
-foreach f : [prog, find_program(py), find_program(progf)]
- ret = run_command(python, f.path())
+foreach f : [prog, progf, py, find_program(py), find_program(progf)]
+ ret = run_command(python, f)
assert(ret.returncode() == 0, 'can\'t manually run @0@'.format(prog.path()))
assert(ret.stdout().strip() == 'Found', 'wrong output from manually-run @0@'.format(prog.path()))
diff --git a/test cases/common/105 find program path/program.py b/test cases/common/105 find program path/program.py
index 2ebc564..2ebc564 100644..100755
--- a/test cases/common/105 find program path/program.py
+++ b/test cases/common/105 find program path/program.py