def find_program_impl(self, args: T.List[mesonlib.FileOrString], for_machine: MachineChoice=MachineChoice.HOST, 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) -> T.Union[('ExternalProgram', 'build.Executable', 'OverrideProgram')]:
    args = mesonlib.listify(args)
    extra_info: T.List[mlog.TV_Loggable] = []
    progobj = self.program_lookup(args, for_machine, required, search_dirs, extra_info)
    if (progobj is None):
        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'))
        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))
    self.store_name_lookups(args)
    if (not silent):
        mlog.log('Program', mlog.bold(progobj.name), 'found:', mlog.green('YES'), *extra_info)
    if isinstance(progobj, build.Executable):
        progobj.was_returned_by_find_program = True
    return progobj
def find_program_impl(self, args: T.List[mesonlib.FileOrString], for_machine: MachineChoice=MachineChoice.HOST, 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) -> T.Union[('ExternalProgram', 'build.Executable', 'OverrideProgram')]:
    args = mesonlib.listify(args)
    extra_info: T.List[mlog.TV_Loggable] = []
    progobj = self.program_lookup(args, for_machine, required, search_dirs, extra_info)
    if (progobj is None):
        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'))
        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))
    self.store_name_lookups(args)
    if (not silent):
        mlog.log('Program', mlog.bold(progobj.name), 'found:', mlog.green('YES'), *extra_info)
    if isinstance(progobj, build.Executable):
        progobj.was_returned_by_find_program = True
    return progobj