Merge pull request #9167 from dcbaker/submit/meson-main-type-checking

Add type annotations and type checking to meson main
pull/9207/head
Jussi Pakkanen 3 years ago committed by GitHub
commit fee5cb697c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .pylintrc
  2. 3
      mesonbuild/backend/backends.py
  3. 27
      mesonbuild/build.py
  4. 1
      mesonbuild/cmake/executor.py
  5. 2
      mesonbuild/compilers/cpp.py
  6. 3
      mesonbuild/compilers/d.py
  7. 1
      mesonbuild/environment.py
  8. 12
      mesonbuild/interpreter/interpreter.py
  9. 279
      mesonbuild/interpreter/mesonmain.py
  10. 2
      mesonbuild/mlog.py
  11. 2
      mesonbuild/modules/__init__.py
  12. 16
      mesonbuild/modules/pkgconfig.py
  13. 3
      mesonbuild/modules/qt.py
  14. 2
      mesonbuild/modules/unstable_external_project.py
  15. 5
      mesonbuild/scripts/meson_exe.py
  16. 1
      run_mypy.py

@ -22,6 +22,7 @@ enable=
mixed-indentation, mixed-indentation,
no-value-for-parameter, no-value-for-parameter,
redundant-keyword-arg, redundant-keyword-arg,
reimported,
singleton-comparison, singleton-comparison,
superfluous-parens, superfluous-parens,
too-many-function-args, too-many-function-args,

@ -1144,7 +1144,8 @@ class Backend:
ifilename = os.path.join(self.environment.get_build_dir(), 'depmf.json') ifilename = os.path.join(self.environment.get_build_dir(), 'depmf.json')
ofilename = os.path.join(self.environment.get_prefix(), self.build.dep_manifest_name) ofilename = os.path.join(self.environment.get_prefix(), self.build.dep_manifest_name)
out_name = os.path.join('{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: with open(ifilename, 'w', encoding='utf-8') as f:
f.write(json.dumps(mfobj)) f.write(json.dumps(mfobj))
# Copy file from, to, and with mode unchanged # Copy file from, to, and with mode unchanged

@ -33,7 +33,7 @@ from .mesonlib import (
extract_as_list, typeslistify, stringlistify, classify_unity_sources, extract_as_list, typeslistify, stringlistify, classify_unity_sources,
get_filenames_templates_dict, substitute_values, has_path_sep, get_filenames_templates_dict, substitute_values, has_path_sep,
OptionKey, PerMachineDefaultable, OptionKey, PerMachineDefaultable,
MesonBugException, FileOrString, MesonBugException,
) )
from .compilers import ( from .compilers import (
Compiler, is_object, clink_langs, sort_clink, lang_suffixes, Compiler, is_object, clink_langs, sort_clink, lang_suffixes,
@ -206,6 +206,19 @@ class InstallDir(HoldableObject):
self.install_tag = install_tag 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: class Build:
"""A class that holds the status of one build including """A class that holds the status of one build including
all dependencies and so on. all dependencies and so on.
@ -230,16 +243,16 @@ class Build:
self.static_linker: PerMachine[StaticLinker] = PerMachine(None, None) self.static_linker: PerMachine[StaticLinker] = PerMachine(None, None)
self.subprojects = {} self.subprojects = {}
self.subproject_dir = '' self.subproject_dir = ''
self.install_scripts = [] self.install_scripts: T.List['ExecutableSerialisation'] = []
self.postconf_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.install_dirs: T.List[InstallDir] = []
self.dep_manifest_name = None self.dep_manifest_name: T.Optional[str] = None
self.dep_manifest = {} self.dep_manifest: T.Dict[str, DepManifest] = {}
self.stdlibs = PerMachine({}, {}) self.stdlibs = PerMachine({}, {})
self.test_setups: T.Dict[str, TestSetup] = {} self.test_setups: T.Dict[str, TestSetup] = {}
self.test_setup_default_name = None 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. 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 # 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: if t in self.kwargs:
self.kwargs[t] = listify(self.kwargs[t], flatten=True) 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'] = [] obj_src: T.List['File'] = []
sources_set = set(self.sources) sources_set = set(self.sources)
for src in srclist: for src in srclist:

@ -28,7 +28,6 @@ from ..mesonlib import PerMachine, Popen_safe, version_compare, MachineChoice, i
from ..programs import find_external_program, NonExistingExternalProgram from ..programs import find_external_program, NonExistingExternalProgram
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
from ..environment import Environment
from ..programs import ExternalProgram from ..programs import ExternalProgram
TYPE_result = T.Tuple[int, T.Optional[str], T.Optional[str]] TYPE_result = T.Tuple[int, T.Optional[str], T.Optional[str]]

@ -47,7 +47,7 @@ if T.TYPE_CHECKING:
from ..environment import Environment from ..environment import Environment
from ..linkers import DynamicLinker from ..linkers import DynamicLinker
from ..programs import ExternalProgram from ..programs import ExternalProgram
from .mixins.clike import CLikeCompiler as CompilerMixinBase CompilerMixinBase = CLikeCompiler
else: else:
CompilerMixinBase = object CompilerMixinBase = object

@ -33,11 +33,12 @@ from .compilers import (
from .mixins.gnu import GnuCompiler from .mixins.gnu import GnuCompiler
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
from .compilers import Compiler as CompilerMixinBase
from ..programs import ExternalProgram from ..programs import ExternalProgram
from ..envconfig import MachineInfo from ..envconfig import MachineInfo
from ..environment import Environment from ..environment import Environment
from ..linkers import DynamicLinker from ..linkers import DynamicLinker
CompilerMixinBase = Compiler
else: else:
CompilerMixinBase = object CompilerMixinBase = object

@ -49,7 +49,6 @@ from mesonbuild import envconfig
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
from configparser import ConfigParser from configparser import ConfigParser
from .dependencies import ExternalProgram
from .wrap.wrap import Resolver from .wrap.wrap import Resolver
build_filename = 'meson.build' build_filename = 'meson.build'

@ -73,7 +73,9 @@ import importlib
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
import argparse import argparse
from . import kwargs from . import kwargs
from ..programs import OverrideProgram
# Input source types passed to Targets # Input source types passed to Targets
SourceInputs = T.Union[mesonlib.File, build.GeneratedList, build.BuildTarget, build.BothLibraries, 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, user_defined_options: T.Optional['argparse.Namespace'] = None,
) -> None: ) -> None:
super().__init__(_build.environment.get_source_dir(), subdir, subproject) super().__init__(_build.environment.get_source_dir(), subdir, subproject)
self.active_projectname = ''
self.build = _build self.build = _build
self.environment = self.build.environment self.environment = self.build.environment
self.coredata = self.environment.get_coredata() 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: if self.build.project_version is None:
self.build.project_version = self.project_version self.build.project_version = self.project_version
proj_license = mesonlib.stringlistify(kwargs.get('license', 'unknown')) proj_license = mesonlib.stringlistify(kwargs.get('license', 'unknown'))
self.build.dep_manifest[proj_name] = {'version': self.project_version, self.build.dep_manifest[proj_name] = build.DepManifest(self.project_version, proj_license)
'license': proj_license}
if self.subproject in self.build.projects: if self.subproject in self.build.projects:
raise InvalidCode('Second call to project().') raise InvalidCode('Second call to project().')
@ -1342,7 +1344,7 @@ external dependencies (including libraries) must go to "dependencies".''')
if isinstance(name, str): if isinstance(name, str):
self.build.searched_programs.add(name) 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: if name in self.build.searched_programs:
raise InterpreterException(f'Tried to override finding of executable "{name}" which has already been found.') raise InterpreterException(f'Tried to override finding of executable "{name}" which has already been found.')
if name in self.build.find_overrides: 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']) @FeatureNewKwargs('find_program', '0.49.0', ['disabler'])
@disablerIfNotFound @disablerIfNotFound
@permittedKwargs({'required', 'native', 'version', 'dirs'}) @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: if not args:
raise InterpreterException('No program name specified.') 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: if self.subproject != buildtarget.subproject:
raise InterpreterException('Tried to extract objects from a different subproject.') raise InterpreterException('Tried to extract objects from a different subproject.')
def is_subproject(self): def is_subproject(self) -> bool:
return self.subproject != '' return self.subproject != ''
@typed_pos_args('set_variable', str, object) @typed_pos_args('set_variable', str, object)

@ -1,4 +1,9 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2012-2021 The Meson development team
# Copyright © 2021 Intel Corporation
import os import os
import typing as T
from .. import mesonlib from .. import mesonlib
from .. import dependencies from .. import dependencies
@ -9,22 +14,33 @@ from ..mesonlib import MachineChoice, OptionKey
from ..programs import OverrideProgram, ExternalProgram from ..programs import OverrideProgram, ExternalProgram
from ..interpreter.type_checking import ENV_KW from ..interpreter.type_checking import ENV_KW
from ..interpreterbase import (MesonInterpreterObject, FeatureNew, FeatureDeprecated, from ..interpreterbase import (MesonInterpreterObject, FeatureNew, FeatureDeprecated,
typed_pos_args, permittedKwargs, noArgsFlattening, noPosargs, noKwargs, typed_pos_args, noArgsFlattening, noPosargs, noKwargs,
typed_kwargs, KwargInfo, MesonVersionString, InterpreterException) typed_kwargs, KwargInfo, MesonVersionString, InterpreterException)
from .interpreterobjects import (ExecutableHolder, ExternalProgramHolder,
CustomTargetHolder, CustomTargetIndexHolder)
from .type_checking import NATIVE_KW, NoneType from .type_checking import NATIVE_KW, NoneType
import typing as T
if T.TYPE_CHECKING: 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 .interpreter import Interpreter
from typing_extensions import TypedDict from typing_extensions import TypedDict
class FuncOverrideDependency(TypedDict): class FuncOverrideDependency(TypedDict):
native: mesonlib.MachineChoice native: mesonlib.MachineChoice
static: T.Optional[bool] static: T.Optional[bool]
class AddInstallScriptKW(TypedDict):
skip_if_destdir: bool
install_tag: str
class NativeKW(TypedDict):
native: mesonlib.MachineChoice
class MesonMain(MesonInterpreterObject): class MesonMain(MesonInterpreterObject):
def __init__(self, build: 'build.Build', interpreter: 'Interpreter'): def __init__(self, build: 'build.Build', interpreter: 'Interpreter'):
super().__init__(subproject=interpreter.subproject) super().__init__(subproject=interpreter.subproject)
@ -61,20 +77,26 @@ class MesonMain(MesonInterpreterObject):
'add_devenv': self.add_devenv_method, '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)): 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, {}) 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 es.subproject = self.interpreter.subproject
return es return es
def _process_script_args( def _process_script_args(
self, name: str, args: T.List[T.Union[ self, name: str, args: T.Sequence[T.Union[
str, mesonlib.File, CustomTargetHolder, str, mesonlib.File, build.Target,
CustomTargetIndexHolder, build.CustomTargetIndex,
ExternalProgramHolder, ExecutableHolder, ExternalProgram, build.Executable,
]], allow_built: bool = False) -> T.List[str]: ]], allow_built: bool = False) -> T.List[str]:
script_args = [] # T.List[str] script_args = [] # T.List[str]
new = False new = False
@ -84,7 +106,7 @@ class MesonMain(MesonInterpreterObject):
elif isinstance(a, mesonlib.File): elif isinstance(a, mesonlib.File):
new = True new = True
script_args.append(a.rel_to_builddir(self.interpreter.environment.source_dir)) 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: if not allow_built:
raise InterpreterException(f'Arguments to {name} cannot be built') raise InterpreterException(f'Arguments to {name} cannot be built')
new = True new = True
@ -98,13 +120,10 @@ class MesonMain(MesonInterpreterObject):
a.target.build_by_default = True a.target.build_by_default = True
else: else:
a.build_by_default = True a.build_by_default = True
elif isinstance(a, ExternalProgram): else:
script_args.extend(a.command) script_args.extend(a.command)
new = True new = True
else:
raise InterpreterException(
f'Arguments to {name} must be strings, Files, or CustomTargets, '
'Indexes of CustomTargets')
if new: if new:
FeatureNew.single_use( FeatureNew.single_use(
f'Calling "{name}" with File, CustomTaget, Index of CustomTarget, ' f'Calling "{name}" with File, CustomTaget, Index of CustomTarget, '
@ -112,39 +131,60 @@ class MesonMain(MesonInterpreterObject):
'0.55.0', self.interpreter.subproject) '0.55.0', self.interpreter.subproject)
return script_args 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( @typed_kwargs(
'add_install_script', 'meson.add_install_script',
KwargInfo('skip_if_destdir', bool, default=False, since='0.57.0'), KwargInfo('skip_if_destdir', bool, default=False, since='0.57.0'),
KwargInfo('install_tag', (str, NoneType), since='0.60.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): def add_install_script_method(
if len(args) < 1: self,
raise InterpreterException('add_install_script takes one or more arguments') 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): if isinstance(args[0], mesonlib.File):
FeatureNew.single_use('Passing file object to script parameter of add_install_script', FeatureNew.single_use('Passing file object to script parameter of add_install_script',
'0.57.0', self.interpreter.subproject) '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 = self._find_source_script(args[0], script_args)
script.skip_if_destdir = kwargs['skip_if_destdir'] script.skip_if_destdir = kwargs['skip_if_destdir']
script.tag = kwargs['install_tag']
self.build.install_scripts.append(script) self.build.install_scripts.append(script)
@permittedKwargs(set()) @typed_pos_args(
def add_postconf_script_method(self, args, kwargs): 'meson.add_postconf_script',
if len(args) < 1: (str, mesonlib.File, ExternalProgram),
raise InterpreterException('add_postconf_script takes one or more arguments') 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): if isinstance(args[0], mesonlib.File):
FeatureNew.single_use('Passing file object to script parameter of add_postconf_script', FeatureNew.single_use('Passing file object to script parameter of add_postconf_script',
'0.57.0', self.interpreter.subproject) '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) script = self._find_source_script(args[0], script_args)
self.build.postconf_scripts.append(script) self.build.postconf_scripts.append(script)
@permittedKwargs(set()) @typed_pos_args(
def add_dist_script_method(self, args, kwargs): 'meson.add_dist_script',
if len(args) < 1: (str, mesonlib.File, build.Executable, ExternalProgram),
raise InterpreterException('add_dist_script takes one or more arguments') varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex)
if len(args) > 1: )
@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', FeatureNew.single_use('Calling "add_dist_script" with multiple arguments',
'0.49.0', self.interpreter.subproject) '0.49.0', self.interpreter.subproject)
if isinstance(args[0], mesonlib.File): if isinstance(args[0], mesonlib.File):
@ -153,13 +193,13 @@ class MesonMain(MesonInterpreterObject):
if self.interpreter.subproject != '': if self.interpreter.subproject != '':
FeatureNew.single_use('Calling "add_dist_script" in a subproject', FeatureNew.single_use('Calling "add_dist_script" in a subproject',
'0.58.0', self.interpreter.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) script = self._find_source_script(args[0], script_args)
self.build.dist_scripts.append(script) self.build.dist_scripts.append(script)
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
def current_source_dir_method(self, args, kwargs): def current_source_dir_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
src = self.interpreter.environment.source_dir src = self.interpreter.environment.source_dir
sub = self.interpreter.subdir sub = self.interpreter.subdir
if sub == '': if sub == '':
@ -167,8 +207,8 @@ class MesonMain(MesonInterpreterObject):
return os.path.join(src, sub) return os.path.join(src, sub)
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
def current_build_dir_method(self, args, kwargs): def current_build_dir_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
src = self.interpreter.environment.build_dir src = self.interpreter.environment.build_dir
sub = self.interpreter.subdir sub = self.interpreter.subdir
if sub == '': if sub == '':
@ -176,26 +216,26 @@ class MesonMain(MesonInterpreterObject):
return os.path.join(src, sub) return os.path.join(src, sub)
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
def backend_method(self, args, kwargs): def backend_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
return self.interpreter.backend.name return self.interpreter.backend.name
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
@FeatureDeprecated('meson.source_root', '0.56.0', 'use meson.project_source_root() or meson.global_source_root() instead.') @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 return self.interpreter.environment.source_dir
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
@FeatureDeprecated('meson.build_root', '0.56.0', 'use meson.project_build_root() or meson.global_build_root() instead.') @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 return self.interpreter.environment.build_dir
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
@FeatureNew('meson.project_source_root', '0.56.0') @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 src = self.interpreter.environment.source_dir
sub = self.interpreter.root_subdir sub = self.interpreter.root_subdir
if sub == '': if sub == '':
@ -203,9 +243,9 @@ class MesonMain(MesonInterpreterObject):
return os.path.join(src, sub) return os.path.join(src, sub)
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
@FeatureNew('meson.project_build_root', '0.56.0') @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 src = self.interpreter.environment.build_dir
sub = self.interpreter.root_subdir sub = self.interpreter.root_subdir
if sub == '': if sub == '':
@ -215,89 +255,77 @@ class MesonMain(MesonInterpreterObject):
@noPosargs @noPosargs
@noKwargs @noKwargs
@FeatureNew('meson.global_source_root', '0.58.0') @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 return self.interpreter.environment.source_dir
@noPosargs @noPosargs
@noKwargs @noKwargs
@FeatureNew('meson.global_build_root', '0.58.0') @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 return self.interpreter.environment.build_dir
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
@FeatureDeprecated('meson.has_exe_wrapper', '0.55.0', 'use meson.can_run_host_binaries instead.') @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: def has_exe_wrapper_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool:
return self.can_run_host_binaries_impl(args, kwargs) return self._can_run_host_binaries_impl()
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
@FeatureNew('meson.can_run_host_binaries', '0.55.0') @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: def can_run_host_binaries_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool:
return self.can_run_host_binaries_impl(args, kwargs) return self._can_run_host_binaries_impl()
def can_run_host_binaries_impl(self, args, kwargs): def _can_run_host_binaries_impl(self) -> bool:
if (self.build.environment.is_cross_build() and return not (
self.build.environment.is_cross_build() and
self.build.environment.need_exe_wrapper() and self.build.environment.need_exe_wrapper() and
self.build.environment.exe_wrapper is None): 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
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
def is_cross_build_method(self, args, kwargs): def is_cross_build_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool:
return self.build.environment.is_cross_build() return self.build.environment.is_cross_build()
@permittedKwargs({'native'}) @typed_pos_args('meson.get_compiler', str)
def get_compiler_method(self, args, kwargs): @typed_kwargs('meson.get_compiler', NATIVE_KW)
if len(args) != 1: def get_compiler_method(self, args: T.Tuple[str], kwargs: 'NativeKW') -> 'Compiler':
raise InterpreterException('get_compiler_method must have one and only one argument.')
cname = args[0] cname = args[0]
for_machine = self.interpreter.machine_from_native_kwarg(kwargs) for_machine = kwargs['native']
clist = self.interpreter.coredata.compilers[for_machine] clist = self.interpreter.coredata.compilers[for_machine]
if cname in clist: try:
return clist[cname] return clist[cname]
except KeyError:
raise InterpreterException(f'Tried to access compiler for language "{cname}", not specified for {for_machine.get_lower_case_name()} machine.') raise InterpreterException(f'Tried to access compiler for language "{cname}", not specified for {for_machine.get_lower_case_name()} machine.')
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
def is_unity_method(self, args, kwargs): def is_unity_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool:
optval = self.interpreter.environment.coredata.get_option(OptionKey('unity')) optval = self.interpreter.environment.coredata.get_option(OptionKey('unity'))
if optval == 'on' or (optval == 'subprojects' and self.interpreter.is_subproject()): return optval == 'on' or (optval == 'subprojects' and self.interpreter.is_subproject())
return True
return False
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
def is_subproject_method(self, args, kwargs): def is_subproject_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool:
return self.interpreter.is_subproject() return self.interpreter.is_subproject()
@permittedKwargs({}) @typed_pos_args('meson.install_dependency_manifest', str)
def install_dependency_manifest_method(self, args, kwargs): @noKwargs
if len(args) != 1: def install_dependency_manifest_method(self, args: T.Tuple[str], kwargs: 'TYPE_kwargs') -> None:
raise InterpreterException('Must specify manifest install file name')
if not isinstance(args[0], str):
raise InterpreterException('Argument must be a string.')
self.build.dep_manifest_name = args[0] self.build.dep_manifest_name = args[0]
@FeatureNew('meson.override_find_program', '0.46.0') @FeatureNew('meson.override_find_program', '0.46.0')
@permittedKwargs({}) @typed_pos_args('meson.override_find_program', str, (mesonlib.File, ExternalProgram, build.Executable))
def override_find_program_method(self, args, kwargs): @noKwargs
if len(args) != 2: def override_find_program_method(self, args: T.Tuple[str, T.Union[mesonlib.File, ExternalProgram, build.Executable]], kwargs: 'TYPE_kwargs') -> None:
raise InterpreterException('Override needs two arguments')
name, exe = args name, exe = args
if not isinstance(name, str):
raise InterpreterException('First argument must be a string')
if isinstance(exe, mesonlib.File): if isinstance(exe, mesonlib.File):
abspath = exe.absolute_path(self.interpreter.environment.source_dir, abspath = exe.absolute_path(self.interpreter.environment.source_dir,
self.interpreter.environment.build_dir) self.interpreter.environment.build_dir)
if not os.path.exists(abspath): if not os.path.exists(abspath):
raise InterpreterException('Tried to override %s with a file that does not exist.' % name) raise InterpreterException(f'Tried to override {name} with a file that does not exist.')
exe = OverrideProgram(name, abspath) exe = OverrideProgram(name, [abspath])
if not isinstance(exe, (ExternalProgram, build.Executable)):
raise InterpreterException('Second argument must be an external program or executable.')
self.interpreter.add_find_program_override(name, exe) self.interpreter.add_find_program_override(name, exe)
@typed_kwargs( @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=None, permissive=True)
self._override_dependency_impl(name, dep, kwargs, static=static) 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: def _override_dependency_impl(self, name: str, dep: dependencies.Dependency, kwargs: 'FuncOverrideDependency',
kwargs = kwargs.copy() 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: if static is None:
del kwargs['static'] del nkwargs['static']
else: else:
kwargs['static'] = static nkwargs['static'] = static
identifier = dependencies.get_dep_identifier(name, kwargs) identifier = dependencies.get_dep_identifier(name, nkwargs)
for_machine = kwargs['native'] for_machine = kwargs['native']
override = self.build.dependency_overrides[for_machine].get(identifier) override = self.build.dependency_overrides[for_machine].get(identifier)
if override: if override:
@ -358,24 +389,24 @@ class MesonMain(MesonInterpreterObject):
build.DependencyOverride(dep, self.interpreter.current_node) build.DependencyOverride(dep, self.interpreter.current_node)
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
def project_version_method(self, args, kwargs): def project_version_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
return self.build.dep_manifest[self.interpreter.active_projectname]['version'] return self.build.dep_manifest[self.interpreter.active_projectname].version
@FeatureNew('meson.project_license()', '0.45.0') @FeatureNew('meson.project_license()', '0.45.0')
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
def project_license_method(self, args, kwargs): 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'] return self.build.dep_manifest[self.interpreter.active_projectname].license
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
def version_method(self, args, kwargs): def version_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> MesonVersionString:
return MesonVersionString(self.interpreter.coredata.version) return MesonVersionString(self.interpreter.coredata.version)
@noPosargs @noPosargs
@permittedKwargs({}) @noKwargs
def project_name_method(self, args, kwargs): def project_name_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str:
return self.interpreter.active_projectname return self.interpreter.active_projectname
def __get_external_property_impl(self, propname: str, fallback: T.Optional[object], machine: MachineChoice) -> object: 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}') raise InterpreterException(f'Unknown property for {machine.get_lower_case_name()} machine: {propname}')
@noArgsFlattening @noArgsFlattening
@permittedKwargs({})
@FeatureDeprecated('meson.get_cross_property', '0.58.0', 'Use meson.get_external_property() instead') @FeatureDeprecated('meson.get_cross_property', '0.58.0', 'Use meson.get_external_property() instead')
@typed_pos_args('meson.get_cross_property', str, optargs=[object]) @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 propname, fallback = args
return self.__get_external_property_impl(propname, fallback, MachineChoice.HOST) return self.__get_external_property_impl(propname, fallback, MachineChoice.HOST)
@noArgsFlattening @noArgsFlattening
@permittedKwargs({'native'})
@FeatureNew('meson.get_external_property', '0.54.0') @FeatureNew('meson.get_external_property', '0.54.0')
@typed_pos_args('meson.get_external_property', str, optargs=[object]) @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 propname, fallback = args
machine = self.interpreter.machine_from_native_kwarg(kwargs) return self.__get_external_property_impl(propname, fallback, kwargs['native'])
return self.__get_external_property_impl(propname, fallback, machine)
@permittedKwargs({'native'})
@FeatureNew('meson.has_external_property', '0.58.0') @FeatureNew('meson.has_external_property', '0.58.0')
@typed_pos_args('meson.has_external_property', str) @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] prop_name = args[0]
for_machine = self.interpreter.machine_from_native_kwarg(kwargs) return prop_name in self.interpreter.environment.properties[kwargs['native']]
return prop_name in self.interpreter.environment.properties[for_machine]
@FeatureNew('add_devenv', '0.58.0') @FeatureNew('add_devenv', '0.58.0')
@noKwargs @noKwargs
@typed_pos_args('add_devenv', (str, list, dict, build.EnvironmentVariables)) @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] env = args[0]
msg = ENV_KW.validator(env) msg = ENV_KW.validator(env)
if msg: if msg:
raise build.InvalidArguments(f'"add_devenv": {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)

@ -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 # 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 # 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}:' return f'{fname}:{lineno}:'
def _log_error(severity: str, *rargs: TV_Loggable, def _log_error(severity: str, *rargs: TV_Loggable,

@ -45,7 +45,7 @@ class ModuleState:
self.current_lineno = interpreter.current_lineno self.current_lineno = interpreter.current_lineno
self.environment = interpreter.environment self.environment = interpreter.environment
self.project_name = interpreter.build.project_name 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: # The backend object is under-used right now, but we will need it:
# https://github.com/mesonbuild/meson/issues/1419 # https://github.com/mesonbuild/meson/issues/1419
self.backend = interpreter.backend self.backend = interpreter.backend

@ -12,18 +12,22 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import os
from pathlib import PurePath from pathlib import PurePath
import os
import typing as T
from . import ExtensionModule
from . import ModuleReturnValue
from .. import build from .. import build
from .. import dependencies from .. import dependencies
from ..dependencies import ThreadDependency
from .. import mesonlib from .. import mesonlib
from .. import mlog from .. import mlog
from . import ModuleReturnValue from ..dependencies import ThreadDependency
from . import ExtensionModule
from ..interpreterbase import permittedKwargs, FeatureNew, FeatureNewKwargs from ..interpreterbase import permittedKwargs, FeatureNew, FeatureNewKwargs
if T.TYPE_CHECKING:
from . import ModuleState
already_warned_objs = set() already_warned_objs = set()
class DependenciesHelper: class DependenciesHelper:
@ -451,8 +455,8 @@ class PkgConfigModule(ExtensionModule):
'install_dir', 'extra_cflags', 'variables', 'url', 'd_module_versions', 'install_dir', 'extra_cflags', 'variables', 'url', 'd_module_versions',
'dataonly', 'conflicts', 'uninstalled_variables', 'dataonly', 'conflicts', 'uninstalled_variables',
'unescaped_variables', 'unescaped_uninstalled_variables'}) 'unescaped_variables', 'unescaped_uninstalled_variables'})
def generate(self, state, args, kwargs): def generate(self, state: 'ModuleState', args, kwargs):
default_version = state.project_version['version'] default_version = state.project_version
default_install_dir = None default_install_dir = None
default_description = None default_description = None
default_name = None default_name = None

@ -13,7 +13,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from mesonbuild import coredata
import os import os
import shutil import shutil
import typing as T import typing as T
@ -21,10 +20,10 @@ import xml.etree.ElementTree as ET
from . import ModuleReturnValue, ExtensionModule from . import ModuleReturnValue, ExtensionModule
from .. import build from .. import build
from .. import coredata
from .. import mlog from .. import mlog
from ..dependencies import find_external_dependency, Dependency, ExternalLibrary from ..dependencies import find_external_dependency, Dependency, ExternalLibrary
from ..mesonlib import MesonException, File, FileOrString, version_compare, Popen_safe from ..mesonlib import MesonException, File, FileOrString, version_compare, Popen_safe
from . import ModuleReturnValue, ExtensionModule
from ..interpreter import extract_required_kwarg from ..interpreter import extract_required_kwarg
from ..interpreter.type_checking import NoneType from ..interpreter.type_checking import NoneType
from ..interpreterbase import ContainerTypeInfo, FeatureDeprecated, KwargInfo, noPosargs, FeatureNew, typed_kwargs from ..interpreterbase import ContainerTypeInfo, FeatureDeprecated, KwargInfo, noPosargs, FeatureNew, typed_kwargs

@ -232,7 +232,7 @@ class ExternalProject(NewExtensionModule):
abs_includedir = Path(abs_includedir, subdir) abs_includedir = Path(abs_includedir, subdir)
abs_libdir = Path(self.install_dir, self.rel_prefix, self.libdir) abs_libdir = Path(self.install_dir, self.rel_prefix, self.libdir)
version = self.project_version['version'] version = self.project_version
incdir = [] incdir = []
compile_args = [f'-I{abs_includedir}'] compile_args = [f'-I{abs_includedir}']
link_args = [f'-L{abs_libdir}', f'-l{libname}'] link_args = [f'-L{abs_libdir}', f'-l{libname}']

@ -32,7 +32,7 @@ def buildparser() -> argparse.ArgumentParser:
parser.add_argument('--feed') parser.add_argument('--feed')
return parser 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 exe.exe_runner:
if not exe.exe_runner.found(): if not exe.exe_runner.found():
raise AssertionError('BUG: Can\'t run cross-compiled exe {!r} with not-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) close_fds=False, stdin=stdin, stdout=pipe, stderr=pipe)
stdout, stderr = p.communicate() stdout, stderr = p.communicate()
if stdin is not None:
stdin.close()
if p.returncode == 0xc0000135: if p.returncode == 0xc0000135:
# STATUS_DLL_NOT_FOUND on Windows indicating a common problem that is otherwise hard to diagnose # STATUS_DLL_NOT_FOUND on Windows indicating a common problem that is otherwise hard to diagnose
raise FileNotFoundError('due to missing DLLs') raise FileNotFoundError('due to missing DLLs')

@ -27,6 +27,7 @@ modules = [
# 'mesonbuild/coredata.py', # 'mesonbuild/coredata.py',
'mesonbuild/envconfig.py', 'mesonbuild/envconfig.py',
'mesonbuild/interpreter/compiler.py', 'mesonbuild/interpreter/compiler.py',
'mesonbuild/interpreter/mesonmain.py',
'mesonbuild/interpreter/interpreterobjects.py', 'mesonbuild/interpreter/interpreterobjects.py',
'mesonbuild/interpreter/type_checking.py', 'mesonbuild/interpreter/type_checking.py',
'mesonbuild/mcompile.py', 'mesonbuild/mcompile.py',

Loading…
Cancel
Save