diff --git a/mesonbuild/modules/unstable_external_project.py b/mesonbuild/modules/unstable_external_project.py index e2e43fc33..6a9496e5c 100644 --- a/mesonbuild/modules/unstable_external_project.py +++ b/mesonbuild/modules/unstable_external_project.py @@ -18,7 +18,7 @@ import shlex import subprocess import typing as T -from . import ExtensionModule, ModuleReturnValue, ModuleState, NewExtensionModule +from . import ExtensionModule, ModuleReturnValue, NewExtensionModule from .. import mlog, build from ..compilers.compilers import CFLAGS_MAPPING, CEXE_MAPPING from ..dependencies import InternalDependency, PkgConfigDependency @@ -27,9 +27,15 @@ from ..interpreterbase import permittedKwargs, typed_pos_args from ..mesonlib import (EnvironmentException, MesonException, Popen_safe, MachineChoice, get_variable_regex, do_replacement, extract_as_list, join_args, OptionKey) +if T.TYPE_CHECKING: + from . import ModuleState + from ..interpreter import Interpreter + from ..interpreterbase import TYPE_var + + class ExternalProject(NewExtensionModule): def __init__(self, - state: ModuleState, + state: 'ModuleState', configure_command: str, configure_options: T.List[str], cross_configure_options: T.List[str], @@ -54,9 +60,15 @@ class ExternalProject(NewExtensionModule): self.src_dir = Path(self.env.get_source_dir(), self.subdir) self.build_dir = Path(self.env.get_build_dir(), self.subdir, 'build') self.install_dir = Path(self.env.get_build_dir(), self.subdir, 'dist') - self.prefix = Path(self.env.coredata.get_option(OptionKey('prefix'))) - self.libdir = Path(self.env.coredata.get_option(OptionKey('libdir'))) - self.includedir = Path(self.env.coredata.get_option(OptionKey('includedir'))) + _p = self.env.coredata.get_option(OptionKey('prefix')) + assert isinstance(_p, str), 'for mypy' + self.prefix = Path(_p) + _l = self.env.coredata.get_option(OptionKey('libdir')) + assert isinstance(_l, str), 'for mypy' + self.libdir = Path(_l) + _i = self.env.coredata.get_option(OptionKey('includedir')) + assert isinstance(_i, str), 'for mypy' + self.includedir = Path(_i) self.name = self.src_dir.name # On Windows if the prefix is "c:/foo" and DESTDIR is "c:/bar", `make` @@ -72,7 +84,7 @@ class ExternalProject(NewExtensionModule): self.targets = self._create_targets() - def _configure(self, state: ModuleState) -> None: + def _configure(self, state: 'ModuleState') -> None: if self.configure_command == 'waf': FeatureNew('Waf external project', '0.60.0').use(self.subproject) waf = state.find_program('waf') @@ -105,18 +117,21 @@ class ExternalProject(NewExtensionModule): configure_cmd += self._format_options(self.cross_configure_options, d) # Set common env variables like CFLAGS, CC, etc. - link_exelist = [] - link_args = [] + link_exelist: T.List[str] = [] + link_args: T.List[str] = [] self.run_env = os.environ.copy() for lang, compiler in self.env.coredata.compilers[MachineChoice.HOST].items(): if any(lang not in i for i in (CEXE_MAPPING, CFLAGS_MAPPING)): continue cargs = self.env.coredata.get_external_args(MachineChoice.HOST, lang) + assert isinstance(cargs, list), 'for mypy' self.run_env[CEXE_MAPPING[lang]] = self._quote_and_join(compiler.get_exelist()) self.run_env[CFLAGS_MAPPING[lang]] = self._quote_and_join(cargs) if not link_exelist: link_exelist = compiler.get_linker_exelist() - link_args = self.env.coredata.get_external_link_args(MachineChoice.HOST, lang) + _l = self.env.coredata.get_external_link_args(MachineChoice.HOST, lang) + assert isinstance(_l, list), 'for mypy' + link_args = _l if link_exelist: # FIXME: Do not pass linker because Meson uses CC as linker wrapper, # but autotools often expects the real linker (e.h. GNU ld). @@ -135,7 +150,7 @@ class ExternalProject(NewExtensionModule): def _quote_and_join(self, array: T.List[str]) -> str: return ' '.join([shlex.quote(i) for i in array]) - def _validate_configure_options(self, variables: T.List[T.Tuple[str, str, str]]): + def _validate_configure_options(self, variables: T.List[T.Tuple[str, str, str]]) -> None: # Ensure the user at least try to pass basic info to the build system, # like the prefix, libdir, etc. for key, default, val in variables: @@ -150,10 +165,10 @@ class ExternalProject(NewExtensionModule): self.configure_options.append(default) def _format_options(self, options: T.List[str], variables: T.List[T.Tuple[str, str, str]]) -> T.List[str]: - out = [] + out: T.List[str] = [] missing = set() regex = get_variable_regex('meson') - confdata = {k: (v, None) for k, d, v in variables} + confdata: T.Dict[str, T.Tuple[str, T.Optional[str]]] = {k: (v, None) for k, _, v in variables} for o in options: arg, missing_vars = do_replacement(regex, o, 'meson', confdata) missing.update(missing_vars) @@ -164,7 +179,7 @@ class ExternalProject(NewExtensionModule): f"Variables {var_list} in configure options are missing.") return out - def _run(self, step: str, command: T.List[str], workdir: Path): + def _run(self, step: str, command: T.List[str], workdir: Path) -> None: mlog.log(f'External project {self.name}:', mlog.bold(step)) m = 'Running command ' + str(command) + ' in directory ' + str(workdir) + '\n' log_filename = Path(mlog.log_dir, f'{self.name}-{step}.log') @@ -175,16 +190,16 @@ class ExternalProject(NewExtensionModule): output.flush() else: mlog.log(m) - p, o, e = Popen_safe(command, cwd=str(workdir), env=self.run_env, - stderr=subprocess.STDOUT, - stdout=output) + p, *_ = Popen_safe(command, cwd=str(workdir), env=self.run_env, + stderr=subprocess.STDOUT, + stdout=output) if p.returncode != 0: m = f'{step} step returned error code {p.returncode}.' if not self.verbose: m += '\nSee logs: ' + str(log_filename) raise MesonException(m) - def _create_targets(self): + def _create_targets(self) -> T.List['TYPE_var']: cmd = self.env.get_build_command() cmd += ['--internal', 'externalproject', '--name', self.name, @@ -220,7 +235,7 @@ class ExternalProject(NewExtensionModule): @permittedKwargs({'subdir'}) @typed_pos_args('external_project.dependency', str) - def dependency_method(self, state, args: T.Tuple[str], kwargs): + def dependency_method(self, state: 'ModuleState', args: T.Tuple[str], kwargs) -> InternalDependency: libname = args[0] subdir = kwargs.get('subdir', '') @@ -234,29 +249,24 @@ class ExternalProject(NewExtensionModule): abs_libdir = Path(self.install_dir, self.rel_prefix, self.libdir) version = self.project_version - incdir = [] compile_args = [f'-I{abs_includedir}'] link_args = [f'-L{abs_libdir}', f'-l{libname}'] - libs = [] - libs_whole = [] sources = self.target - final_deps = [] - variables = {} - dep = InternalDependency(version, incdir, compile_args, link_args, libs, - libs_whole, sources, final_deps, variables) + dep = InternalDependency(version, [], compile_args, link_args, [], + [], [sources], [], {}) return dep class ExternalProjectModule(ExtensionModule): @FeatureNew('External build system Module', '0.56.0') - def __init__(self, interpreter): + def __init__(self, interpreter: 'Interpreter'): super().__init__(interpreter) self.methods.update({'add_project': self.add_project, }) @permittedKwargs({'configure_options', 'cross_configure_options', 'verbose', 'env'}) @typed_pos_args('external_project_mod.add_project', str) - def add_project(self, state: ModuleState, args: T.Tuple[str], kwargs: T.Dict[str, T.Any]): + def add_project(self, state: 'ModuleState', args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> ModuleReturnValue: configure_command = args[0] configure_options = extract_as_list(kwargs, 'configure_options') cross_configure_options = extract_as_list(kwargs, 'cross_configure_options') @@ -272,5 +282,5 @@ class ExternalProjectModule(ExtensionModule): return ModuleReturnValue(project, project.targets) -def initialize(*args, **kwargs): - return ExternalProjectModule(*args, **kwargs) +def initialize(interp: 'Interpreter') -> ExternalProjectModule: + return ExternalProjectModule(interp)