aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/interpreter.py
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2018-04-16 22:22:02 +0300
committerGitHub <noreply@github.com>2018-04-16 22:22:02 +0300
commit0e00470d8c9711e62848a1d697d156cbab66e0bc (patch)
tree192047ead98b0c212f5b6b5b730f3f7d9ed87157 /mesonbuild/interpreter.py
parent5e45f4c621f14176478e3160e2bb3c6c77796b41 (diff)
parent6cdd14fc4eca8bddd4716ab5a9ebf09476846e6b (diff)
downloadmeson-0e00470d8c9711e62848a1d697d156cbab66e0bc.zip
meson-0e00470d8c9711e62848a1d697d156cbab66e0bc.tar.gz
meson-0e00470d8c9711e62848a1d697d156cbab66e0bc.tar.bz2
Merge pull request #3218 from mesonbuild/findoverrider
Make it possible to override find_program [skip ci]
Diffstat (limited to 'mesonbuild/interpreter.py')
-rw-r--r--mesonbuild/interpreter.py110
1 files changed, 85 insertions, 25 deletions
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index b99a413..a130312 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1304,6 +1304,7 @@ class MesonMain(InterpreterObject):
'add_install_script': self.add_install_script_method,
'add_postconf_script': self.add_postconf_script_method,
'install_dependency_manifest': self.install_dependency_manifest_method,
+ 'override_find_program': self.override_find_program_method,
'project_version': self.project_version_method,
'project_license': self.project_license_method,
'version': self.version_method,
@@ -1416,6 +1417,26 @@ class MesonMain(InterpreterObject):
raise InterpreterException('Argument must be a string.')
self.build.dep_manifest_name = args[0]
+ def override_find_program_method(self, args, kwargs):
+ if len(args) != 2:
+ raise InterpreterException('Override needs two arguments')
+ name = args[0]
+ exe = args[1]
+ if not isinstance(name, str):
+ raise InterpreterException('First argument must be a string')
+ if hasattr(exe, 'held_object'):
+ exe = exe.held_object
+ if isinstance(exe, mesonlib.File):
+ abspath = exe.absolute_path(self.interpreter.environment.source_dir,
+ self.interpreter.environment.build_dir)
+ if not os.path.exists(abspath):
+ raise InterpreterException('Tried to override %s with a file that does not exist.' % name)
+ exe = dependencies.ExternalProgram(abspath)
+ if not isinstance(exe, dependencies.ExternalProgram):
+ # FIXME, make this work if the exe is an Executable target.
+ raise InterpreterException('Second argument must be an external program.')
+ self.interpreter.add_find_program_override(name, exe)
+
def project_version_method(self, args, kwargs):
return self.build.dep_manifest[self.interpreter.active_projectname]['version']
@@ -1493,7 +1514,7 @@ permitted_kwargs = {'add_global_arguments': {'language'},
class Interpreter(InterpreterBase):
def __init__(self, build, backend, subproject='', subdir='', subproject_dir='subprojects',
- default_project_options=[]):
+ modules = None, default_project_options=[]):
super().__init__(build.environment.get_source_dir(), subdir)
self.an_unpicklable_object = mesonlib.an_unpicklable_object
self.build = build
@@ -1501,6 +1522,10 @@ class Interpreter(InterpreterBase):
self.coredata = self.environment.get_coredata()
self.backend = backend
self.subproject = subproject
+ if modules is None:
+ self.modules = {}
+ else:
+ self.modules = modules
# Subproject directory is usually the name of the subproject, but can
# be different for dependencies provided by wrap files.
self.subproject_directory_name = subdir.split(os.path.sep)[-1]
@@ -1681,13 +1706,13 @@ class Interpreter(InterpreterBase):
plainname = modname.split('-', 1)[1]
mlog.warning('Module %s has no backwards or forwards compatibility and might not exist in future releases.' % modname, location=node)
modname = 'unstable_' + plainname
- if modname not in self.environment.coredata.modules:
+ if modname not in self.modules:
try:
module = importlib.import_module('mesonbuild.modules.' + modname)
except ImportError:
raise InvalidArguments('Module "%s" does not exist' % (modname, ))
- self.environment.coredata.modules[modname] = module.initialize()
- return ModuleHolder(modname, self.environment.coredata.modules[modname], self)
+ self.modules[modname] = module.initialize(self)
+ return ModuleHolder(modname, self.modules[modname], self)
@stringArgs
@noKwargs
@@ -1864,15 +1889,16 @@ external dependencies (including libraries) must go to "dependencies".''')
self.global_args_frozen = True
mlog.log()
with mlog.nested():
- mlog.log('Executing subproject ', mlog.bold(dirname), '.\n', sep='')
+ mlog.log('\nExecuting subproject ', mlog.bold(dirname), '.\n', sep='')
subi = Interpreter(self.build, self.backend, dirname, subdir, self.subproject_dir,
- mesonlib.stringlistify(kwargs.get('default_options', [])))
+ self.modules, mesonlib.stringlistify(kwargs.get('default_options', [])))
subi.subprojects = self.subprojects
subi.subproject_stack = self.subproject_stack + [dirname]
current_active = self.active_projectname
subi.run()
mlog.log('\nSubproject', mlog.bold(dirname), 'finished.')
+
if 'version' in kwargs:
pv = subi.project_version
wanted = kwargs['version']
@@ -2225,7 +2251,7 @@ to directly access options of other subprojects.''')
break
self.coredata.base_options[optname] = oobj
- def program_from_cross_file(self, prognames):
+ def program_from_cross_file(self, prognames, silent=False):
bins = self.environment.cross_info.config['binaries']
for p in prognames:
if hasattr(p, 'held_object'):
@@ -2236,11 +2262,11 @@ to directly access options of other subprojects.''')
raise InterpreterException('Executable name must be a string.')
if p in bins:
exename = bins[p]
- extprog = dependencies.ExternalProgram(exename)
+ extprog = dependencies.ExternalProgram(exename, silent=silent)
progobj = ExternalProgramHolder(extprog)
return progobj
- def program_from_system(self, args):
+ def program_from_system(self, args, 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.
@@ -2259,11 +2285,55 @@ to directly access options of other subprojects.''')
else:
raise InvalidArguments('find_program only accepts strings and '
'files, not {!r}'.format(exename))
- extprog = dependencies.ExternalProgram(exename, search_dir=search_dir)
+ extprog = dependencies.ExternalProgram(exename, search_dir=search_dir,
+ silent=silent)
progobj = ExternalProgramHolder(extprog)
if progobj.found():
return progobj
+ def program_from_overrides(self, command_names, silent=False):
+ for name in command_names:
+ if not isinstance(name, str):
+ continue
+ if name in self.build.find_overrides:
+ exe = self.build.find_overrides[name]
+ if not silent:
+ mlog.log('Program', mlog.bold(name), 'found:', mlog.green('YES'),
+ '(overridden: %s)' % ' '.join(exe.command))
+ return ExternalProgramHolder(exe)
+ return None
+
+ def store_name_lookups(self, command_names):
+ for name in command_names:
+ if isinstance(name, str):
+ self.build.searched_programs.add(name)
+
+ def add_find_program_override(self, name, exe):
+ if name in self.build.searched_programs:
+ raise InterpreterException('Tried to override finding of executable "%s" which has already been found.'
+ % name)
+ if name in self.build.find_overrides:
+ raise InterpreterException('Tried to override executable "%s" which has already been overridden.'
+ % name)
+ self.build.find_overrides[name] = exe
+
+ def find_program_impl(self, args, native=False, required=True, silent=True):
+ if not isinstance(args, list):
+ args = [args]
+ progobj = self.program_from_overrides(args, silent=silent)
+ if progobj is None and self.build.environment.is_cross_build():
+ if not native:
+ progobj = self.program_from_cross_file(args, silent=silent)
+ if progobj is None:
+ progobj = self.program_from_system(args, silent=silent)
+ if required and (progobj is None or not progobj.found()):
+ raise InvalidArguments('Program(s) {!r} not found or not executable'.format(args))
+ if progobj is None:
+ return ExternalProgramHolder(dependencies.NonExistingExternalProgram())
+ # Only store successful lookups
+ self.store_name_lookups(args)
+ return progobj
+
@permittedKwargs(permitted_kwargs['find_program'])
def func_find_program(self, node, args, kwargs):
if not args:
@@ -2271,20 +2341,10 @@ to directly access options of other subprojects.''')
required = kwargs.get('required', True)
if not isinstance(required, bool):
raise InvalidArguments('"required" argument must be a boolean.')
- progobj = None
- if self.build.environment.is_cross_build():
- use_native = kwargs.get('native', False)
- if not isinstance(use_native, bool):
- raise InvalidArguments('Argument to "native" must be a boolean.')
- if not use_native:
- progobj = self.program_from_cross_file(args)
- if progobj is None:
- progobj = self.program_from_system(args)
- if required and (progobj is None or not progobj.found()):
- raise InvalidArguments('Program(s) {!r} not found or not executable'.format(args))
- if progobj is None:
- return ExternalProgramHolder(dependencies.NonExistingExternalProgram())
- return progobj
+ use_native = kwargs.get('native', False)
+ if not isinstance(use_native, bool):
+ raise InvalidArguments('Argument to "native" must be a boolean.')
+ return self.find_program_impl(args, native=use_native, required=required, silent=False)
def func_find_library(self, node, args, kwargs):
raise InvalidCode('find_library() is removed, use meson.get_compiler(\'name\').find_library() instead.\n'
@@ -2691,7 +2751,7 @@ root and issuing %s.
exe = args[1]
if not isinstance(exe, (ExecutableHolder, JarHolder, ExternalProgramHolder)):
if isinstance(exe, mesonlib.File):
- exe = self.func_find_program(node, (args[1], ), {})
+ exe = self.func_find_program(node, args[1], {})
else:
raise InterpreterException('Second argument must be executable.')
par = kwargs.get('is_parallel', True)