diff --git a/.pylintrc b/.pylintrc index e811d08cc..eae06672a 100644 --- a/.pylintrc +++ b/.pylintrc @@ -22,6 +22,7 @@ enable= mixed-indentation, no-value-for-parameter, redundant-keyword-arg, + reimported, singleton-comparison, superfluous-parens, too-many-function-args, diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 4570b0033..bc2b74ac3 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -1144,7 +1144,8 @@ class Backend: ifilename = os.path.join(self.environment.get_build_dir(), 'depmf.json') ofilename = os.path.join(self.environment.get_prefix(), self.build.dep_manifest_name) out_name = os.path.join('{prefix}', self.build.dep_manifest_name) - mfobj = {'type': 'dependency manifest', 'version': '1.0', 'projects': self.build.dep_manifest} + mfobj = {'type': 'dependency manifest', 'version': '1.0', + 'projects': {k: v.to_json() for k, v in self.build.dep_manifest.items()}} with open(ifilename, 'w', encoding='utf-8') as f: f.write(json.dumps(mfobj)) # Copy file from, to, and with mode unchanged diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 149841546..2ee2d4a3e 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -33,7 +33,7 @@ from .mesonlib import ( extract_as_list, typeslistify, stringlistify, classify_unity_sources, get_filenames_templates_dict, substitute_values, has_path_sep, OptionKey, PerMachineDefaultable, - MesonBugException, FileOrString, + MesonBugException, ) from .compilers import ( Compiler, is_object, clink_langs, sort_clink, lang_suffixes, @@ -206,6 +206,19 @@ class InstallDir(HoldableObject): self.install_tag = install_tag +class DepManifest: + + def __init__(self, version: str, license: T.List[str]): + self.version = version + self.license = license + + def to_json(self) -> T.Dict[str, T.Union[str, T.List[str]]]: + return { + 'version': self.version, + 'license': self.license, + } + + class Build: """A class that holds the status of one build including all dependencies and so on. @@ -230,16 +243,16 @@ class Build: self.static_linker: PerMachine[StaticLinker] = PerMachine(None, None) self.subprojects = {} self.subproject_dir = '' - self.install_scripts = [] + self.install_scripts: T.List['ExecutableSerialisation'] = [] self.postconf_scripts: T.List['ExecutableSerialisation'] = [] - self.dist_scripts = [] + self.dist_scripts: T.List['ExecutableSerialisation'] = [] self.install_dirs: T.List[InstallDir] = [] - self.dep_manifest_name = None - self.dep_manifest = {} + self.dep_manifest_name: T.Optional[str] = None + self.dep_manifest: T.Dict[str, DepManifest] = {} self.stdlibs = PerMachine({}, {}) self.test_setups: T.Dict[str, TestSetup] = {} self.test_setup_default_name = None - self.find_overrides = {} + self.find_overrides: T.Dict[str, T.Union['Executable', programs.ExternalProgram, programs.OverrideProgram]] = {} self.searched_programs = set() # The list of all programs that have been searched for. # If we are doing a cross build we need two caches, if we're doing a @@ -921,7 +934,7 @@ class BuildTarget(Target): if t in self.kwargs: self.kwargs[t] = listify(self.kwargs[t], flatten=True) - def extract_objects(self, srclist: T.List[FileOrString]) -> ExtractedObjects: + def extract_objects(self, srclist: T.List['FileOrString']) -> ExtractedObjects: obj_src: T.List['File'] = [] sources_set = set(self.sources) for src in srclist: diff --git a/mesonbuild/cmake/executor.py b/mesonbuild/cmake/executor.py index 7b06f2623..65ff7308d 100644 --- a/mesonbuild/cmake/executor.py +++ b/mesonbuild/cmake/executor.py @@ -28,7 +28,6 @@ from ..mesonlib import PerMachine, Popen_safe, version_compare, MachineChoice, i from ..programs import find_external_program, NonExistingExternalProgram if T.TYPE_CHECKING: - from ..environment import Environment from ..programs import ExternalProgram TYPE_result = T.Tuple[int, T.Optional[str], T.Optional[str]] diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 168ba7a40..ecc911d72 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -47,7 +47,7 @@ if T.TYPE_CHECKING: from ..environment import Environment from ..linkers import DynamicLinker from ..programs import ExternalProgram - from .mixins.clike import CLikeCompiler as CompilerMixinBase + CompilerMixinBase = CLikeCompiler else: CompilerMixinBase = object diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index 19706c50c..18a5d6815 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -33,11 +33,12 @@ from .compilers import ( from .mixins.gnu import GnuCompiler if T.TYPE_CHECKING: - from .compilers import Compiler as CompilerMixinBase from ..programs import ExternalProgram from ..envconfig import MachineInfo from ..environment import Environment from ..linkers import DynamicLinker + + CompilerMixinBase = Compiler else: CompilerMixinBase = object diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index a50908711..2369439a0 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -49,7 +49,6 @@ from mesonbuild import envconfig if T.TYPE_CHECKING: from configparser import ConfigParser - from .dependencies import ExternalProgram from .wrap.wrap import Resolver build_filename = 'meson.build' diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 2d04d2dfa..f94ed2dcf 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -73,7 +73,9 @@ import importlib if T.TYPE_CHECKING: import argparse + from . import kwargs + from ..programs import OverrideProgram # Input source types passed to Targets SourceInputs = T.Union[mesonlib.File, build.GeneratedList, build.BuildTarget, build.BothLibraries, @@ -233,6 +235,7 @@ class Interpreter(InterpreterBase, HoldableObject): user_defined_options: T.Optional['argparse.Namespace'] = None, ) -> None: super().__init__(_build.environment.get_source_dir(), subdir, subproject) + self.active_projectname = '' self.build = _build self.environment = self.build.environment self.coredata = self.environment.get_coredata() @@ -1057,8 +1060,7 @@ external dependencies (including libraries) must go to "dependencies".''') if self.build.project_version is None: self.build.project_version = self.project_version proj_license = mesonlib.stringlistify(kwargs.get('license', 'unknown')) - self.build.dep_manifest[proj_name] = {'version': self.project_version, - 'license': proj_license} + self.build.dep_manifest[proj_name] = build.DepManifest(self.project_version, proj_license) if self.subproject in self.build.projects: raise InvalidCode('Second call to project().') @@ -1342,7 +1344,7 @@ external dependencies (including libraries) must go to "dependencies".''') if isinstance(name, str): self.build.searched_programs.add(name) - def add_find_program_override(self, name, exe): + def add_find_program_override(self, name: str, exe: T.Union[build.Executable, ExternalProgram, 'OverrideProgram']) -> None: if name in self.build.searched_programs: raise InterpreterException(f'Tried to override finding of executable "{name}" which has already been found.') if name in self.build.find_overrides: @@ -1435,7 +1437,7 @@ external dependencies (including libraries) must go to "dependencies".''') @FeatureNewKwargs('find_program', '0.49.0', ['disabler']) @disablerIfNotFound @permittedKwargs({'required', 'native', 'version', 'dirs'}) - def func_find_program(self, node, args, kwargs): + def func_find_program(self, node, args, kwargs) -> T.Union['build.Executable', ExternalProgram, 'OverrideProgram']: if not args: raise InterpreterException('No program name specified.') @@ -2648,7 +2650,7 @@ This will become a hard error in the future.''', location=self.current_node) if self.subproject != buildtarget.subproject: raise InterpreterException('Tried to extract objects from a different subproject.') - def is_subproject(self): + def is_subproject(self) -> bool: return self.subproject != '' @typed_pos_args('set_variable', str, object) diff --git a/mesonbuild/interpreter/mesonmain.py b/mesonbuild/interpreter/mesonmain.py index 9c4f50ada..637ca72ee 100644 --- a/mesonbuild/interpreter/mesonmain.py +++ b/mesonbuild/interpreter/mesonmain.py @@ -1,4 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2012-2021 The Meson development team +# Copyright © 2021 Intel Corporation + import os +import typing as T from .. import mesonlib from .. import dependencies @@ -9,22 +14,33 @@ from ..mesonlib import MachineChoice, OptionKey from ..programs import OverrideProgram, ExternalProgram from ..interpreter.type_checking import ENV_KW from ..interpreterbase import (MesonInterpreterObject, FeatureNew, FeatureDeprecated, - typed_pos_args, permittedKwargs, noArgsFlattening, noPosargs, noKwargs, + typed_pos_args, noArgsFlattening, noPosargs, noKwargs, typed_kwargs, KwargInfo, MesonVersionString, InterpreterException) - -from .interpreterobjects import (ExecutableHolder, ExternalProgramHolder, - CustomTargetHolder, CustomTargetIndexHolder) from .type_checking import NATIVE_KW, NoneType -import typing as T - if T.TYPE_CHECKING: + from ..backend.backends import ExecutableSerialisation + from ..compilers import Compiler + from ..interpreterbase import TYPE_kwargs, TYPE_var from .interpreter import Interpreter + from typing_extensions import TypedDict + class FuncOverrideDependency(TypedDict): + native: mesonlib.MachineChoice static: T.Optional[bool] + class AddInstallScriptKW(TypedDict): + + skip_if_destdir: bool + install_tag: str + + class NativeKW(TypedDict): + + native: mesonlib.MachineChoice + + class MesonMain(MesonInterpreterObject): def __init__(self, build: 'build.Build', interpreter: 'Interpreter'): super().__init__(subproject=interpreter.subproject) @@ -61,20 +77,26 @@ class MesonMain(MesonInterpreterObject): 'add_devenv': self.add_devenv_method, }) - def _find_source_script(self, prog: T.Union[str, mesonlib.File, build.Executable, ExternalProgram], args): - + def _find_source_script( + self, prog: T.Union[str, mesonlib.File, build.Executable, ExternalProgram], + args: T.List[str]) -> 'ExecutableSerialisation': + largs: T.List[T.Union[str, build.Executable, ExternalProgram]] = [] if isinstance(prog, (build.Executable, ExternalProgram)): - return self.interpreter.backend.get_executable_serialisation([prog] + args) + largs.append(prog) + largs.extend(args) + return self.interpreter.backend.get_executable_serialisation(largs) found = self.interpreter.func_find_program({}, prog, {}) - es = self.interpreter.backend.get_executable_serialisation([found] + args) + largs.append(found) + largs.extend(args) + es = self.interpreter.backend.get_executable_serialisation(largs) es.subproject = self.interpreter.subproject return es def _process_script_args( - self, name: str, args: T.List[T.Union[ - str, mesonlib.File, CustomTargetHolder, - CustomTargetIndexHolder, - ExternalProgramHolder, ExecutableHolder, + self, name: str, args: T.Sequence[T.Union[ + str, mesonlib.File, build.Target, + build.CustomTargetIndex, + ExternalProgram, build.Executable, ]], allow_built: bool = False) -> T.List[str]: script_args = [] # T.List[str] new = False @@ -84,7 +106,7 @@ class MesonMain(MesonInterpreterObject): elif isinstance(a, mesonlib.File): new = True script_args.append(a.rel_to_builddir(self.interpreter.environment.source_dir)) - elif isinstance(a, (build.BuildTarget, build.CustomTarget, build.CustomTargetIndex)): + elif isinstance(a, (build.Target, build.CustomTargetIndex)): if not allow_built: raise InterpreterException(f'Arguments to {name} cannot be built') new = True @@ -98,13 +120,10 @@ class MesonMain(MesonInterpreterObject): a.target.build_by_default = True else: a.build_by_default = True - elif isinstance(a, ExternalProgram): + else: script_args.extend(a.command) new = True - else: - raise InterpreterException( - f'Arguments to {name} must be strings, Files, or CustomTargets, ' - 'Indexes of CustomTargets') + if new: FeatureNew.single_use( f'Calling "{name}" with File, CustomTaget, Index of CustomTarget, ' @@ -112,39 +131,60 @@ class MesonMain(MesonInterpreterObject): '0.55.0', self.interpreter.subproject) return script_args + @typed_pos_args( + 'meson.add_install_script', + (str, mesonlib.File, build.Executable, ExternalProgram), + varargs=(str, mesonlib.File, build.Target, build.CustomTargetIndex, ExternalProgram) + ) @typed_kwargs( - 'add_install_script', + 'meson.add_install_script', KwargInfo('skip_if_destdir', bool, default=False, since='0.57.0'), KwargInfo('install_tag', (str, NoneType), since='0.60.0'), ) - def add_install_script_method(self, args: 'T.Tuple[T.Union[str, mesonlib.File, ExecutableHolder], T.Union[str, mesonlib.File, CustomTargetHolder, CustomTargetIndexHolder], ...]', kwargs): - if len(args) < 1: - raise InterpreterException('add_install_script takes one or more arguments') + def add_install_script_method( + self, + args: T.Tuple[T.Union[str, mesonlib.File, build.Executable, ExternalProgram], + T.List[T.Union[str, mesonlib.File, build.Target, build.CustomTargetIndex, ExternalProgram]]], + kwargs: 'AddInstallScriptKW') -> None: if isinstance(args[0], mesonlib.File): FeatureNew.single_use('Passing file object to script parameter of add_install_script', '0.57.0', self.interpreter.subproject) - script_args = self._process_script_args('add_install_script', args[1:], allow_built=True) + + script_args = self._process_script_args('add_install_script', args[1], allow_built=True) script = self._find_source_script(args[0], script_args) script.skip_if_destdir = kwargs['skip_if_destdir'] - script.tag = kwargs['install_tag'] self.build.install_scripts.append(script) - @permittedKwargs(set()) - def add_postconf_script_method(self, args, kwargs): - if len(args) < 1: - raise InterpreterException('add_postconf_script takes one or more arguments') + @typed_pos_args( + 'meson.add_postconf_script', + (str, mesonlib.File, ExternalProgram), + varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex) + ) + @noKwargs + def add_postconf_script_method( + self, + args: T.Tuple[T.Union[str, mesonlib.File, ExternalProgram], + T.List[T.Union[str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex]]], + kwargs: 'TYPE_kwargs') -> None: if isinstance(args[0], mesonlib.File): FeatureNew.single_use('Passing file object to script parameter of add_postconf_script', '0.57.0', self.interpreter.subproject) - script_args = self._process_script_args('add_postconf_script', args[1:], allow_built=True) + script_args = self._process_script_args('add_postconf_script', args[1], allow_built=True) script = self._find_source_script(args[0], script_args) self.build.postconf_scripts.append(script) - @permittedKwargs(set()) - def add_dist_script_method(self, args, kwargs): - if len(args) < 1: - raise InterpreterException('add_dist_script takes one or more arguments') - if len(args) > 1: + @typed_pos_args( + 'meson.add_dist_script', + (str, mesonlib.File, build.Executable, ExternalProgram), + varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex) + ) + @noKwargs + def add_dist_script_method( + self, + args: T.Tuple[T.Union[str, mesonlib.File, build.Executable, ExternalProgram], + T.List[T.Union[str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex]]], + kwargs: 'TYPE_kwargs') -> None: + if args[1]: FeatureNew.single_use('Calling "add_dist_script" with multiple arguments', '0.49.0', self.interpreter.subproject) if isinstance(args[0], mesonlib.File): @@ -153,13 +193,13 @@ class MesonMain(MesonInterpreterObject): if self.interpreter.subproject != '': FeatureNew.single_use('Calling "add_dist_script" in a subproject', '0.58.0', self.interpreter.subproject) - script_args = self._process_script_args('add_dist_script', args[1:], allow_built=True) + script_args = self._process_script_args('add_dist_script', args[1], allow_built=True) script = self._find_source_script(args[0], script_args) self.build.dist_scripts.append(script) @noPosargs - @permittedKwargs({}) - def current_source_dir_method(self, args, kwargs): + @noKwargs + def current_source_dir_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: src = self.interpreter.environment.source_dir sub = self.interpreter.subdir if sub == '': @@ -167,8 +207,8 @@ class MesonMain(MesonInterpreterObject): return os.path.join(src, sub) @noPosargs - @permittedKwargs({}) - def current_build_dir_method(self, args, kwargs): + @noKwargs + def current_build_dir_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: src = self.interpreter.environment.build_dir sub = self.interpreter.subdir if sub == '': @@ -176,26 +216,26 @@ class MesonMain(MesonInterpreterObject): return os.path.join(src, sub) @noPosargs - @permittedKwargs({}) - def backend_method(self, args, kwargs): + @noKwargs + def backend_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.interpreter.backend.name @noPosargs - @permittedKwargs({}) + @noKwargs @FeatureDeprecated('meson.source_root', '0.56.0', 'use meson.project_source_root() or meson.global_source_root() instead.') - def source_root_method(self, args, kwargs): + def source_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.interpreter.environment.source_dir @noPosargs - @permittedKwargs({}) + @noKwargs @FeatureDeprecated('meson.build_root', '0.56.0', 'use meson.project_build_root() or meson.global_build_root() instead.') - def build_root_method(self, args, kwargs): + def build_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.interpreter.environment.build_dir @noPosargs - @permittedKwargs({}) + @noKwargs @FeatureNew('meson.project_source_root', '0.56.0') - def project_source_root_method(self, args, kwargs): + def project_source_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: src = self.interpreter.environment.source_dir sub = self.interpreter.root_subdir if sub == '': @@ -203,9 +243,9 @@ class MesonMain(MesonInterpreterObject): return os.path.join(src, sub) @noPosargs - @permittedKwargs({}) + @noKwargs @FeatureNew('meson.project_build_root', '0.56.0') - def project_build_root_method(self, args, kwargs): + def project_build_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: src = self.interpreter.environment.build_dir sub = self.interpreter.root_subdir if sub == '': @@ -215,89 +255,77 @@ class MesonMain(MesonInterpreterObject): @noPosargs @noKwargs @FeatureNew('meson.global_source_root', '0.58.0') - def global_source_root_method(self, args, kwargs): + def global_source_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.interpreter.environment.source_dir @noPosargs @noKwargs @FeatureNew('meson.global_build_root', '0.58.0') - def global_build_root_method(self, args, kwargs): + def global_build_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.interpreter.environment.build_dir @noPosargs - @permittedKwargs({}) + @noKwargs @FeatureDeprecated('meson.has_exe_wrapper', '0.55.0', 'use meson.can_run_host_binaries instead.') - def has_exe_wrapper_method(self, args: T.Tuple[object, ...], kwargs: T.Dict[str, object]) -> bool: - return self.can_run_host_binaries_impl(args, kwargs) + def has_exe_wrapper_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: + return self._can_run_host_binaries_impl() @noPosargs - @permittedKwargs({}) + @noKwargs @FeatureNew('meson.can_run_host_binaries', '0.55.0') - def can_run_host_binaries_method(self, args: T.Tuple[object, ...], kwargs: T.Dict[str, object]) -> bool: - return self.can_run_host_binaries_impl(args, kwargs) + def can_run_host_binaries_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: + return self._can_run_host_binaries_impl() - def can_run_host_binaries_impl(self, args, kwargs): - if (self.build.environment.is_cross_build() and + def _can_run_host_binaries_impl(self) -> bool: + return not ( + self.build.environment.is_cross_build() and self.build.environment.need_exe_wrapper() and - self.build.environment.exe_wrapper is None): - return False - # We return True when exe_wrap is defined, when it's not needed, or - # when we're compiling natively. - return True + self.build.environment.exe_wrapper is None + ) @noPosargs - @permittedKwargs({}) - def is_cross_build_method(self, args, kwargs): + @noKwargs + def is_cross_build_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: return self.build.environment.is_cross_build() - @permittedKwargs({'native'}) - def get_compiler_method(self, args, kwargs): - if len(args) != 1: - raise InterpreterException('get_compiler_method must have one and only one argument.') + @typed_pos_args('meson.get_compiler', str) + @typed_kwargs('meson.get_compiler', NATIVE_KW) + def get_compiler_method(self, args: T.Tuple[str], kwargs: 'NativeKW') -> 'Compiler': cname = args[0] - for_machine = self.interpreter.machine_from_native_kwarg(kwargs) + for_machine = kwargs['native'] clist = self.interpreter.coredata.compilers[for_machine] - if cname in clist: + try: return clist[cname] - raise InterpreterException(f'Tried to access compiler for language "{cname}", not specified for {for_machine.get_lower_case_name()} machine.') + except KeyError: + raise InterpreterException(f'Tried to access compiler for language "{cname}", not specified for {for_machine.get_lower_case_name()} machine.') @noPosargs - @permittedKwargs({}) - def is_unity_method(self, args, kwargs): + @noKwargs + def is_unity_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: optval = self.interpreter.environment.coredata.get_option(OptionKey('unity')) - if optval == 'on' or (optval == 'subprojects' and self.interpreter.is_subproject()): - return True - return False + return optval == 'on' or (optval == 'subprojects' and self.interpreter.is_subproject()) @noPosargs - @permittedKwargs({}) - def is_subproject_method(self, args, kwargs): + @noKwargs + def is_subproject_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: return self.interpreter.is_subproject() - @permittedKwargs({}) - def install_dependency_manifest_method(self, args, kwargs): - if len(args) != 1: - raise InterpreterException('Must specify manifest install file name') - if not isinstance(args[0], str): - raise InterpreterException('Argument must be a string.') + @typed_pos_args('meson.install_dependency_manifest', str) + @noKwargs + def install_dependency_manifest_method(self, args: T.Tuple[str], kwargs: 'TYPE_kwargs') -> None: self.build.dep_manifest_name = args[0] @FeatureNew('meson.override_find_program', '0.46.0') - @permittedKwargs({}) - def override_find_program_method(self, args, kwargs): - if len(args) != 2: - raise InterpreterException('Override needs two arguments') + @typed_pos_args('meson.override_find_program', str, (mesonlib.File, ExternalProgram, build.Executable)) + @noKwargs + def override_find_program_method(self, args: T.Tuple[str, T.Union[mesonlib.File, ExternalProgram, build.Executable]], kwargs: 'TYPE_kwargs') -> None: name, exe = args - if not isinstance(name, str): - raise InterpreterException('First argument must be a string') 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 = OverrideProgram(name, abspath) - if not isinstance(exe, (ExternalProgram, build.Executable)): - raise InterpreterException('Second argument must be an external program or executable.') + raise InterpreterException(f'Tried to override {name} with a file that does not exist.') + exe = OverrideProgram(name, [abspath]) self.interpreter.add_find_program_override(name, exe) @typed_kwargs( @@ -339,13 +367,16 @@ class MesonMain(MesonInterpreterObject): self._override_dependency_impl(name, dep, kwargs, static=None, permissive=True) self._override_dependency_impl(name, dep, kwargs, static=static) - def _override_dependency_impl(self, name: str, dep: dependencies.Dependency, kwargs: 'FuncOverrideDependency', static: T.Optional[bool], permissive: bool = False) -> None: - kwargs = kwargs.copy() + def _override_dependency_impl(self, name: str, dep: dependencies.Dependency, kwargs: 'FuncOverrideDependency', + static: T.Optional[bool], permissive: bool = False) -> None: + # We need the cast here as get_dep_identifier works on such a dict, + # which FuncOverrideDependency is, but mypy can't fgure that out + nkwargs = T.cast(T.Dict[str, T.Any], kwargs.copy()) if static is None: - del kwargs['static'] + del nkwargs['static'] else: - kwargs['static'] = static - identifier = dependencies.get_dep_identifier(name, kwargs) + nkwargs['static'] = static + identifier = dependencies.get_dep_identifier(name, nkwargs) for_machine = kwargs['native'] override = self.build.dependency_overrides[for_machine].get(identifier) if override: @@ -358,24 +389,24 @@ class MesonMain(MesonInterpreterObject): build.DependencyOverride(dep, self.interpreter.current_node) @noPosargs - @permittedKwargs({}) - def project_version_method(self, args, kwargs): - return self.build.dep_manifest[self.interpreter.active_projectname]['version'] + @noKwargs + def project_version_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: + return self.build.dep_manifest[self.interpreter.active_projectname].version @FeatureNew('meson.project_license()', '0.45.0') @noPosargs - @permittedKwargs({}) - def project_license_method(self, args, kwargs): - return self.build.dep_manifest[self.interpreter.active_projectname]['license'] + @noKwargs + def project_license_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> T.List[str]: + return self.build.dep_manifest[self.interpreter.active_projectname].license @noPosargs - @permittedKwargs({}) - def version_method(self, args, kwargs): + @noKwargs + def version_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> MesonVersionString: return MesonVersionString(self.interpreter.coredata.version) @noPosargs - @permittedKwargs({}) - def project_name_method(self, args, kwargs): + @noKwargs + def project_name_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.interpreter.active_projectname def __get_external_property_impl(self, propname: str, fallback: T.Optional[object], machine: MachineChoice) -> object: @@ -388,37 +419,37 @@ class MesonMain(MesonInterpreterObject): raise InterpreterException(f'Unknown property for {machine.get_lower_case_name()} machine: {propname}') @noArgsFlattening - @permittedKwargs({}) @FeatureDeprecated('meson.get_cross_property', '0.58.0', 'Use meson.get_external_property() instead') @typed_pos_args('meson.get_cross_property', str, optargs=[object]) - def get_cross_property_method(self, args: T.Tuple[str, T.Optional[object]], kwargs: T.Dict[str, T.Any]) -> object: + @noKwargs + def get_cross_property_method(self, args: T.Tuple[str, T.Optional[object]], kwargs: 'TYPE_kwargs') -> object: propname, fallback = args return self.__get_external_property_impl(propname, fallback, MachineChoice.HOST) @noArgsFlattening - @permittedKwargs({'native'}) @FeatureNew('meson.get_external_property', '0.54.0') @typed_pos_args('meson.get_external_property', str, optargs=[object]) - def get_external_property_method(self, args: T.Tuple[str, T.Optional[object]], kwargs: T.Dict[str, T.Any]) -> object: + @typed_kwargs('meson.get_external_property', NATIVE_KW) + def get_external_property_method(self, args: T.Tuple[str, T.Optional[object]], kwargs: 'NativeKW') -> object: propname, fallback = args - machine = self.interpreter.machine_from_native_kwarg(kwargs) - return self.__get_external_property_impl(propname, fallback, machine) + return self.__get_external_property_impl(propname, fallback, kwargs['native']) - @permittedKwargs({'native'}) @FeatureNew('meson.has_external_property', '0.58.0') @typed_pos_args('meson.has_external_property', str) - def has_external_property_method(self, args: T.Tuple[str], kwargs: T.Dict[str, T.Any]) -> str: + @typed_kwargs('meson.has_external_property', NATIVE_KW) + def has_external_property_method(self, args: T.Tuple[str], kwargs: 'NativeKW') -> bool: prop_name = args[0] - for_machine = self.interpreter.machine_from_native_kwarg(kwargs) - return prop_name in self.interpreter.environment.properties[for_machine] + return prop_name in self.interpreter.environment.properties[kwargs['native']] @FeatureNew('add_devenv', '0.58.0') @noKwargs @typed_pos_args('add_devenv', (str, list, dict, build.EnvironmentVariables)) - def add_devenv_method(self, args: T.Tuple[T.Union[str, list, dict, build.EnvironmentVariables]], kwargs: T.Dict[str, T.Any]) -> None: + def add_devenv_method(self, args: T.Tuple[T.Union[str, list, dict, build.EnvironmentVariables]], kwargs: 'TYPE_kwargs') -> None: env = args[0] msg = ENV_KW.validator(env) if msg: raise build.InvalidArguments(f'"add_devenv": {msg}') - self.build.devenv.append(ENV_KW.convertor(env)) + converted = ENV_KW.convertor(env) + assert isinstance(converted, build.EnvironmentVariables) + self.build.devenv.append(converted) diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py index da9e2a53a..18cbc4818 100644 --- a/mesonbuild/mlog.py +++ b/mesonbuild/mlog.py @@ -293,7 +293,7 @@ def log_once(*args: TV_Loggable, is_error: bool = False, # # This would more accurately embody what this function can handle, but we # don't have that yet, so instead we'll do some casting to work around it -def get_error_location_string(fname: str, lineno: str) -> str: +def get_error_location_string(fname: str, lineno: int) -> str: return f'{fname}:{lineno}:' def _log_error(severity: str, *rargs: TV_Loggable, diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index 8f641200a..0129909a5 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -45,7 +45,7 @@ class ModuleState: self.current_lineno = interpreter.current_lineno self.environment = interpreter.environment self.project_name = interpreter.build.project_name - self.project_version = interpreter.build.dep_manifest[interpreter.active_projectname] + self.project_version = interpreter.build.dep_manifest[interpreter.active_projectname].version # The backend object is under-used right now, but we will need it: # https://github.com/mesonbuild/meson/issues/1419 self.backend = interpreter.backend diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index f73e16882..7be479667 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -12,18 +12,22 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os from pathlib import PurePath +import os +import typing as T +from . import ExtensionModule +from . import ModuleReturnValue from .. import build from .. import dependencies -from ..dependencies import ThreadDependency from .. import mesonlib from .. import mlog -from . import ModuleReturnValue -from . import ExtensionModule +from ..dependencies import ThreadDependency from ..interpreterbase import permittedKwargs, FeatureNew, FeatureNewKwargs +if T.TYPE_CHECKING: + from . import ModuleState + already_warned_objs = set() class DependenciesHelper: @@ -451,8 +455,8 @@ class PkgConfigModule(ExtensionModule): 'install_dir', 'extra_cflags', 'variables', 'url', 'd_module_versions', 'dataonly', 'conflicts', 'uninstalled_variables', 'unescaped_variables', 'unescaped_uninstalled_variables'}) - def generate(self, state, args, kwargs): - default_version = state.project_version['version'] + def generate(self, state: 'ModuleState', args, kwargs): + default_version = state.project_version default_install_dir = None default_description = None default_name = None diff --git a/mesonbuild/modules/qt.py b/mesonbuild/modules/qt.py index 19d9a6395..7dafad735 100644 --- a/mesonbuild/modules/qt.py +++ b/mesonbuild/modules/qt.py @@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from mesonbuild import coredata import os import shutil import typing as T @@ -21,10 +20,10 @@ import xml.etree.ElementTree as ET from . import ModuleReturnValue, ExtensionModule from .. import build +from .. import coredata from .. import mlog from ..dependencies import find_external_dependency, Dependency, ExternalLibrary from ..mesonlib import MesonException, File, FileOrString, version_compare, Popen_safe -from . import ModuleReturnValue, ExtensionModule from ..interpreter import extract_required_kwarg from ..interpreter.type_checking import NoneType from ..interpreterbase import ContainerTypeInfo, FeatureDeprecated, KwargInfo, noPosargs, FeatureNew, typed_kwargs diff --git a/mesonbuild/modules/unstable_external_project.py b/mesonbuild/modules/unstable_external_project.py index 8bd3c1c4a..87b0ab694 100644 --- a/mesonbuild/modules/unstable_external_project.py +++ b/mesonbuild/modules/unstable_external_project.py @@ -232,7 +232,7 @@ class ExternalProject(NewExtensionModule): abs_includedir = Path(abs_includedir, subdir) abs_libdir = Path(self.install_dir, self.rel_prefix, self.libdir) - version = self.project_version['version'] + version = self.project_version incdir = [] compile_args = [f'-I{abs_includedir}'] link_args = [f'-L{abs_libdir}', f'-l{libname}'] diff --git a/mesonbuild/scripts/meson_exe.py b/mesonbuild/scripts/meson_exe.py index 9c1ae596c..dc89876be 100644 --- a/mesonbuild/scripts/meson_exe.py +++ b/mesonbuild/scripts/meson_exe.py @@ -32,7 +32,7 @@ def buildparser() -> argparse.ArgumentParser: parser.add_argument('--feed') return parser -def run_exe(exe: ExecutableSerialisation, extra_env: T.Optional[dict] = None) -> int: +def run_exe(exe: ExecutableSerialisation, extra_env: T.Optional[T.Dict[str, str]] = None) -> int: if exe.exe_runner: if not exe.exe_runner.found(): raise AssertionError('BUG: Can\'t run cross-compiled exe {!r} with not-found ' @@ -67,6 +67,9 @@ def run_exe(exe: ExecutableSerialisation, extra_env: T.Optional[dict] = None) -> close_fds=False, stdin=stdin, stdout=pipe, stderr=pipe) stdout, stderr = p.communicate() + if stdin is not None: + stdin.close() + if p.returncode == 0xc0000135: # STATUS_DLL_NOT_FOUND on Windows indicating a common problem that is otherwise hard to diagnose raise FileNotFoundError('due to missing DLLs') diff --git a/run_mypy.py b/run_mypy.py index f6add90a0..e5b2bbea6 100755 --- a/run_mypy.py +++ b/run_mypy.py @@ -27,6 +27,7 @@ modules = [ # 'mesonbuild/coredata.py', 'mesonbuild/envconfig.py', 'mesonbuild/interpreter/compiler.py', + 'mesonbuild/interpreter/mesonmain.py', 'mesonbuild/interpreter/interpreterobjects.py', 'mesonbuild/interpreter/type_checking.py', 'mesonbuild/mcompile.py',