parent
6f87215f1f
commit
f720105e24
|
@ -131,6 +131,8 @@ if T.TYPE_CHECKING:
|
|||
|
||||
BuildTargetSource = T.Union[mesonlib.FileOrString, build.GeneratedTypes, build.StructuredSources]
|
||||
|
||||
ProgramVersionFunc = T.Callable[[T.Union[ExternalProgram, build.Executable, OverrideProgram]], str]
|
||||
|
||||
|
||||
def _project_version_validator(value: T.Union[T.List, str, mesonlib.File, None]) -> T.Optional[str]:
|
||||
if isinstance(value, list):
|
||||
|
@ -1621,46 +1623,23 @@ class Interpreter(InterpreterBase, HoldableObject):
|
|||
required: bool = True, silent: bool = True,
|
||||
wanted: T.Union[str, T.List[str]] = '',
|
||||
search_dirs: T.Optional[T.List[str]] = None,
|
||||
version_func: T.Optional[T.Callable[[T.Union['ExternalProgram', 'build.Executable', 'OverrideProgram']], str]] = None
|
||||
version_func: T.Optional[ProgramVersionFunc] = None
|
||||
) -> T.Union['ExternalProgram', 'build.Executable', 'OverrideProgram']:
|
||||
args = mesonlib.listify(args)
|
||||
|
||||
extra_info: T.List[mlog.TV_Loggable] = []
|
||||
progobj = self.program_lookup(args, for_machine, default_options, required, search_dirs, extra_info)
|
||||
if progobj is None:
|
||||
progobj = self.program_lookup(args, for_machine, default_options, required, search_dirs, wanted, version_func, extra_info)
|
||||
if progobj is None or not self.check_program_version(progobj, wanted, version_func, extra_info):
|
||||
progobj = self.notfound_program(args)
|
||||
|
||||
if isinstance(progobj, ExternalProgram) and not progobj.found():
|
||||
if not silent:
|
||||
mlog.log('Program', mlog.bold(progobj.get_name()), 'found:', mlog.red('NO'))
|
||||
mlog.log('Program', mlog.bold(progobj.get_name()), 'found:', mlog.red('NO'), *extra_info)
|
||||
if required:
|
||||
m = 'Program {!r} not found or not executable'
|
||||
raise InterpreterException(m.format(progobj.get_name()))
|
||||
return progobj
|
||||
|
||||
if wanted:
|
||||
if version_func:
|
||||
version = version_func(progobj)
|
||||
elif isinstance(progobj, build.Executable):
|
||||
if progobj.subproject:
|
||||
interp = self.subprojects[progobj.subproject].held_object
|
||||
else:
|
||||
interp = self
|
||||
assert isinstance(interp, Interpreter)
|
||||
version = interp.project_version
|
||||
else:
|
||||
version = progobj.get_version(self)
|
||||
is_found, not_found, _ = mesonlib.version_compare_many(version, wanted)
|
||||
if not is_found:
|
||||
mlog.log('Program', mlog.bold(progobj.name), 'found:', mlog.red('NO'),
|
||||
'found', mlog.normal_cyan(version), 'but need:',
|
||||
mlog.bold(', '.join([f"'{e}'" for e in not_found])), *extra_info)
|
||||
if required:
|
||||
m = 'Invalid version of program, need {!r} {!r} found {!r}.'
|
||||
raise InterpreterException(m.format(progobj.name, not_found, version))
|
||||
return self.notfound_program(args)
|
||||
extra_info.insert(0, mlog.normal_cyan(version))
|
||||
|
||||
# Only store successful lookups
|
||||
self.store_name_lookups(args)
|
||||
if not silent:
|
||||
|
@ -1671,7 +1650,11 @@ class Interpreter(InterpreterBase, HoldableObject):
|
|||
|
||||
def program_lookup(self, args: T.List[mesonlib.FileOrString], for_machine: MachineChoice,
|
||||
default_options: T.Optional[T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]]],
|
||||
required: bool, search_dirs: T.List[str], extra_info: T.List[mlog.TV_Loggable]
|
||||
required: bool,
|
||||
search_dirs: T.List[str],
|
||||
wanted: T.Union[str, T.List[str]],
|
||||
version_func: T.Optional[ProgramVersionFunc],
|
||||
extra_info: T.List[mlog.TV_Loggable]
|
||||
) -> T.Optional[T.Union[ExternalProgram, build.Executable, OverrideProgram]]:
|
||||
progobj = self.program_from_overrides(args, extra_info)
|
||||
if progobj:
|
||||
|
@ -1694,11 +1677,42 @@ class Interpreter(InterpreterBase, HoldableObject):
|
|||
if progobj is None and args[0].endswith('python3'):
|
||||
prog = ExternalProgram('python3', mesonlib.python_command, silent=True)
|
||||
progobj = prog if prog.found() else None
|
||||
|
||||
if progobj and not self.check_program_version(progobj, wanted, version_func, extra_info):
|
||||
progobj = None
|
||||
|
||||
if progobj is None and fallback and required:
|
||||
progobj = self.notfound_program(args)
|
||||
mlog.log('Program', mlog.bold(progobj.get_name()), 'found:', mlog.red('NO'), *extra_info)
|
||||
extra_info.clear()
|
||||
progobj = self.find_program_fallback(fallback, args, default_options, required, extra_info)
|
||||
|
||||
return progobj
|
||||
|
||||
def check_program_version(self, progobj: T.Union[ExternalProgram, build.Executable, OverrideProgram],
|
||||
wanted: T.Union[str, T.List[str]],
|
||||
version_func: T.Optional[ProgramVersionFunc],
|
||||
extra_info: T.List[mlog.TV_Loggable]) -> bool:
|
||||
if wanted:
|
||||
if version_func:
|
||||
version = version_func(progobj)
|
||||
elif isinstance(progobj, build.Executable):
|
||||
if progobj.subproject:
|
||||
interp = self.subprojects[progobj.subproject].held_object
|
||||
else:
|
||||
interp = self
|
||||
assert isinstance(interp, Interpreter)
|
||||
version = interp.project_version
|
||||
else:
|
||||
version = progobj.get_version(self)
|
||||
is_found, not_found, _ = mesonlib.version_compare_many(version, wanted)
|
||||
if not is_found:
|
||||
extra_info[:0] = ['found', mlog.normal_cyan(version), 'but need:',
|
||||
mlog.bold(', '.join([f"'{e}'" for e in not_found]))]
|
||||
return False
|
||||
extra_info.insert(0, mlog.normal_cyan(version))
|
||||
return True
|
||||
|
||||
def find_program_fallback(self, fallback: str, args: T.List[mesonlib.FileOrString],
|
||||
default_options: T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]],
|
||||
required: bool, extra_info: T.List[mlog.TV_Loggable]
|
||||
|
|
|
@ -26,6 +26,7 @@ from ..programs import ExternalProgram
|
|||
|
||||
if T.TYPE_CHECKING:
|
||||
from ..interpreter import Interpreter
|
||||
from ..interpreter.interpreter import ProgramVersionFunc
|
||||
from ..interpreter.interpreterobjects import MachineHolder
|
||||
from ..interpreterbase import TYPE_var, TYPE_kwargs
|
||||
from ..programs import OverrideProgram
|
||||
|
@ -86,7 +87,7 @@ class ModuleState:
|
|||
|
||||
def find_program(self, prog: T.Union[mesonlib.FileOrString, T.List[mesonlib.FileOrString]],
|
||||
required: bool = True,
|
||||
version_func: T.Optional[T.Callable[[T.Union[ExternalProgram, build.Executable, OverrideProgram]], str]] = None,
|
||||
version_func: T.Optional[ProgramVersionFunc] = None,
|
||||
wanted: T.Optional[str] = None, silent: bool = False,
|
||||
for_machine: MachineChoice = MachineChoice.HOST) -> T.Union[ExternalProgram, build.Executable, OverrideProgram]:
|
||||
if not isinstance(prog, list):
|
||||
|
|
|
@ -23,3 +23,9 @@ six_prog = find_program('six_meson_exe')
|
|||
assert(six_prog.found())
|
||||
assert(six_prog.full_path() != '')
|
||||
assert(six_prog.full_path() == six_prog.path())
|
||||
|
||||
# We have prog-version.py in current directory, but it's version 1.0.
|
||||
# This needs to use fallback for "prog-version" name which will be version 2.0.
|
||||
prog = find_program('prog-version.py', 'prog-version', version: '>= 2.0')
|
||||
assert(prog.found())
|
||||
assert(prog.version() == '2.0')
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
#! /usr/bin/env python3
|
||||
|
||||
print('1.0')
|
|
@ -0,0 +1,5 @@
|
|||
[wrap-file]
|
||||
directory = sub2
|
||||
|
||||
[provide]
|
||||
program_names = prog-version
|
|
@ -0,0 +1,4 @@
|
|||
project('sub2')
|
||||
|
||||
prog = find_program('prog-version.py')
|
||||
meson.override_find_program('prog-version', prog)
|
|
@ -0,0 +1,3 @@
|
|||
#! /usr/bin/env python3
|
||||
|
||||
print('2.0')
|
Loading…
Reference in New Issue