diff options
Diffstat (limited to 'mesonbuild/interpreter/interpreter.py')
-rw-r--r-- | mesonbuild/interpreter/interpreter.py | 70 |
1 files changed, 42 insertions, 28 deletions
diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 7bba4fa..4751af9 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -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] |