aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.com>2019-12-03 22:05:07 -0500
committerXavier Claessens <xclaesse@gmail.com>2019-12-05 16:52:22 -0500
commitb87209946859a642f048391ca6cb6ef57edf0522 (patch)
tree6dea0d577b7c044a800f669c43db83a0cf8502ad
parent691a74aec2a34540cce8c1a86f4874bd0814a65c (diff)
downloadmeson-b87209946859a642f048391ca6cb6ef57edf0522.zip
meson-b87209946859a642f048391ca6cb6ef57edf0522.tar.gz
meson-b87209946859a642f048391ca6cb6ef57edf0522.tar.bz2
find_program(): Add 'dirs' keyword argument
Fixes: #1576
-rw-r--r--docs/markdown/Reference-manual.md3
-rw-r--r--docs/markdown/snippets/find_program.md9
-rw-r--r--mesonbuild/dependencies/base.py11
-rw-r--r--mesonbuild/interpreter.py41
-rw-r--r--test cases/common/28 find program/meson.build6
-rw-r--r--test cases/common/28 find program/scripts/test_subdir.py3
6 files changed, 56 insertions, 17 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index dd0b3f4..9762955 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -701,6 +701,9 @@ Keyword arguments are the following:
If the output is more complicated than that, the version checking will have to
be done manually using [`run_command()`](#run_command).
+- `dirs` *(since 0.53.0)* Extra list of absolute paths where to look for program
+ names.
+
Meson will also autodetect scripts with a shebang line and run them
with the executable/interpreter specified in it both on Windows
(because the command invocator will reject the command otherwise) and
diff --git a/docs/markdown/snippets/find_program.md b/docs/markdown/snippets/find_program.md
new file mode 100644
index 0000000..2bef824
--- /dev/null
+++ b/docs/markdown/snippets/find_program.md
@@ -0,0 +1,9 @@
+## Search directories for `find_program()`
+
+It is now possible to give a list of absolute paths where `find_program()` should
+also search, using the `dirs` keyword argument.
+
+For example on Linux `/sbin` and `/usr/sbin` are not always in the `$PATH`:
+```meson
+prog = find_program('mytool', dirs : ['/usr/sbin', '/sbin'])
+```
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index d11aebf..258a4fb 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -1699,12 +1699,19 @@ class ExternalProgram:
for_machine = MachineChoice.BUILD
def __init__(self, name: str, command: Optional[List[str]] = None,
- silent: bool = False, search_dir: Optional[str] = None):
+ silent: bool = False, search_dir: Optional[str] = None,
+ extra_search_dirs: Optional[List[str]] = None):
self.name = name
if command is not None:
self.command = listify(command)
else:
- self.command = self._search(name, search_dir)
+ all_search_dirs = [search_dir]
+ if extra_search_dirs:
+ all_search_dirs += extra_search_dirs
+ for d in all_search_dirs:
+ self.command = self._search(name, d)
+ if self.found():
+ break
# Set path to be the last item that is actually a file (in order to
# skip options in something like ['python', '-u', 'file.py']. If we
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index e402afb..d3a40f7 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -119,6 +119,18 @@ def extract_required_kwarg(kwargs, subproject, feature_check=None, default=True)
return disabled, required, feature
+def extract_search_dirs(kwargs):
+ search_dirs = mesonlib.stringlistify(kwargs.get('dirs', []))
+ search_dirs = [Path(d).expanduser() for d in search_dirs]
+ for d in search_dirs:
+ if mesonlib.is_windows() and d.root.startswith('\\'):
+ # a Unix-path starting with `/` that is not absolute on Windows.
+ # discard without failing for end-user ease of cross-platform directory arrays
+ continue
+ if not d.is_absolute():
+ raise InvalidCode('Search directory {} is not an absolute path.'.format(d))
+ return list(map(str, search_dirs))
+
class TryRunResultHolder(InterpreterObject):
def __init__(self, res):
super().__init__()
@@ -1554,16 +1566,7 @@ class CompilerHolder(InterpreterObject):
if not self.has_header_method([h], has_header_kwargs):
return self.notfound_library(libname)
- search_dirs = mesonlib.stringlistify(kwargs.get('dirs', []))
- search_dirs = [Path(d).expanduser() for d in search_dirs]
- for d in search_dirs:
- if mesonlib.is_windows() and d.root.startswith('\\'):
- # a Unix-path starting with `/` that is not absolute on Windows.
- # discard without failing for end-user ease of cross-platform directory arrays
- continue
- if not d.is_absolute():
- raise InvalidCode('Search directory {} is not an absolute path.'.format(d))
- search_dirs = list(map(str, search_dirs))
+ search_dirs = extract_search_dirs(kwargs)
libtype = mesonlib.LibType.PREFER_SHARED
if 'static' in kwargs:
@@ -2036,7 +2039,7 @@ permitted_kwargs = {'add_global_arguments': {'language', 'native'},
'version',
},
'executable': build.known_exe_kwargs,
- 'find_program': {'required', 'native', 'version'},
+ 'find_program': {'required', 'native', 'version', 'dirs'},
'generator': {'arguments',
'output',
'depends',
@@ -2896,7 +2899,7 @@ external dependencies (including libraries) must go to "dependencies".''')
return ExternalProgramHolder(prog)
return None
- def program_from_system(self, args, silent=False):
+ def program_from_system(self, args, search_dirs, silent=False):
# Search for scripts relative to current subdir.
# Do not cache found programs because find_program('foobar')
# might give different results when run from different source dirs.
@@ -2910,12 +2913,15 @@ external dependencies (including libraries) must go to "dependencies".''')
search_dir = os.path.join(self.environment.get_source_dir(),
exename.subdir)
exename = exename.fname
+ extra_search_dirs = []
elif isinstance(exename, str):
search_dir = source_dir
+ extra_search_dirs = search_dirs
else:
raise InvalidArguments('find_program only accepts strings and '
'files, not {!r}'.format(exename))
extprog = dependencies.ExternalProgram(exename, search_dir=search_dir,
+ extra_search_dirs=extra_search_dirs,
silent=silent)
progobj = ExternalProgramHolder(extprog)
if progobj.found():
@@ -2949,7 +2955,8 @@ external dependencies (including libraries) must go to "dependencies".''')
# TODO update modules to always pass `for_machine`. It is bad-form to assume
# the host machine.
- def find_program_impl(self, args, for_machine: MachineChoice = MachineChoice.HOST, required=True, silent=True, wanted=''):
+ def find_program_impl(self, args, for_machine: MachineChoice = MachineChoice.HOST,
+ required=True, silent=True, wanted='', search_dirs=None):
if not isinstance(args, list):
args = [args]
@@ -2957,7 +2964,7 @@ external dependencies (including libraries) must go to "dependencies".''')
if progobj is None:
progobj = self.program_from_file_for(for_machine, args, silent=silent)
if progobj is None:
- progobj = self.program_from_system(args, silent=silent)
+ progobj = self.program_from_system(args, search_dirs, silent=silent)
if progobj is None and args[0].endswith('python3'):
prog = dependencies.ExternalProgram('python3', mesonlib.python_command, silent=True)
progobj = ExternalProgramHolder(prog)
@@ -2980,6 +2987,7 @@ external dependencies (including libraries) must go to "dependencies".''')
return ExternalProgramHolder(dependencies.NonExistingExternalProgram())
return progobj
+ @FeatureNewKwargs('find_program', '0.53.0', ['dirs'])
@FeatureNewKwargs('find_program', '0.52.0', ['version'])
@FeatureNewKwargs('find_program', '0.49.0', ['disabler'])
@disablerIfNotFound
@@ -2993,9 +3001,12 @@ external dependencies (including libraries) must go to "dependencies".''')
mlog.log('Program', mlog.bold(' '.join(args)), 'skipped: feature', mlog.bold(feature), 'disabled')
return ExternalProgramHolder(dependencies.NonExistingExternalProgram())
+ search_dirs = extract_search_dirs(kwargs)
wanted = mesonlib.stringlistify(kwargs.get('version', []))
for_machine = self.machine_from_native_kwarg(kwargs)
- return self.find_program_impl(args, for_machine, required=required, silent=False, wanted=wanted)
+ return self.find_program_impl(args, for_machine, required=required,
+ silent=False, wanted=wanted,
+ search_dirs=search_dirs)
def func_find_library(self, node, args, kwargs):
raise InvalidCode('find_library() is removed, use meson.get_compiler(\'name\').find_library() instead.\n'
diff --git a/test cases/common/28 find program/meson.build b/test cases/common/28 find program/meson.build
index 983b7b4..3b59caa 100644
--- a/test cases/common/28 find program/meson.build
+++ b/test cases/common/28 find program/meson.build
@@ -27,3 +27,9 @@ assert(prog.found(), 'Program version should match')
prog = find_program('print-version-with-prefix.py', version : '>=1.0')
assert(prog.found(), 'Program version should match')
+
+prog = find_program('test_subdir.py', required : false)
+assert(not prog.found(), 'Program should not be found')
+
+prog = find_program('test_subdir.py', dirs : ['/donotexist', meson.current_source_dir() / 'scripts'])
+assert(prog.found(), 'Program should be found')
diff --git a/test cases/common/28 find program/scripts/test_subdir.py b/test cases/common/28 find program/scripts/test_subdir.py
new file mode 100644
index 0000000..947ffe4
--- /dev/null
+++ b/test cases/common/28 find program/scripts/test_subdir.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python3
+
+exit(0)