Merge pull request #8103 from dcbaker/submit/module-typing-cleanups
Fix some layering violations and add some type annotations in the interpreter
This commit is contained in:
commit
c415bc6cfb
|
@ -39,6 +39,7 @@ from .interpreterbase import FeatureNew
|
|||
|
||||
if T.TYPE_CHECKING:
|
||||
from .interpreter import Test
|
||||
from .mesonlib import FileMode, FileOrString
|
||||
|
||||
pch_kwargs = set(['c_pch', 'cpp_pch'])
|
||||
|
||||
|
@ -122,6 +123,52 @@ class DependencyOverride:
|
|||
self.node = node
|
||||
self.explicit = explicit
|
||||
|
||||
class Headers:
|
||||
|
||||
def __init__(self, sources: T.List[File], install_subdir: T.Optional[str],
|
||||
install_dir: T.Optional[str], install_mode: T.Optional['FileMode']):
|
||||
self.sources = sources
|
||||
self.install_subdir = install_subdir
|
||||
self.custom_install_dir = install_dir
|
||||
self.custom_install_mode = install_mode
|
||||
|
||||
# TODO: we really don't need any of these methods, but they're preserved to
|
||||
# keep APIs relying on them working.
|
||||
|
||||
def set_install_subdir(self, subdir: str) -> None:
|
||||
self.install_subdir = subdir
|
||||
|
||||
def get_install_subdir(self) -> str:
|
||||
return self.install_subdir
|
||||
|
||||
def get_sources(self) -> T.List[File]:
|
||||
return self.sources
|
||||
|
||||
def get_custom_install_dir(self) -> T.Optional[str]:
|
||||
return self.custom_install_dir
|
||||
|
||||
def get_custom_install_mode(self) -> T.Optional['FileMode']:
|
||||
return self.custom_install_mode
|
||||
|
||||
|
||||
class Man:
|
||||
|
||||
def __init__(self, sources: T.List[File], install_dir: T.Optional[str],
|
||||
install_mode: T.Optional['FileMode']):
|
||||
self.sources = sources
|
||||
self.custom_install_dir = install_dir
|
||||
self.custom_install_mode = install_mode
|
||||
|
||||
def get_custom_install_dir(self) -> T.Optional[str]:
|
||||
return self.custom_install_dir
|
||||
|
||||
def get_custom_install_mode(self) -> T.Optional['FileMode']:
|
||||
return self.custom_install_mode
|
||||
|
||||
def get_sources(self) -> T.List['File']:
|
||||
return self.sources
|
||||
|
||||
|
||||
class Build:
|
||||
"""A class that holds the status of one build including
|
||||
all dependencies and so on.
|
||||
|
@ -132,18 +179,18 @@ class Build:
|
|||
self.project_version = None
|
||||
self.environment = environment
|
||||
self.projects = {}
|
||||
self.targets = OrderedDict() # type: T.Dict[str, 'Target']
|
||||
self.run_target_names = set() # type: T.Set[T.Tuple[str, str]]
|
||||
self.global_args = PerMachine({}, {}) # type: PerMachine[T.Dict[str, T.List[str]]]
|
||||
self.projects_args = PerMachine({}, {}) # type: PerMachine[T.Dict[str, T.List[str]]]
|
||||
self.global_link_args = PerMachine({}, {}) # type: PerMachine[T.Dict[str, T.List[str]]]
|
||||
self.projects_link_args = PerMachine({}, {}) # type: PerMachine[T.Dict[str, T.List[str]]]
|
||||
self.tests = [] # type: T.List['Test']
|
||||
self.benchmarks = [] # type: T.List['Test']
|
||||
self.headers = []
|
||||
self.man = []
|
||||
self.data = []
|
||||
self.static_linker = PerMachine(None, None) # type: PerMachine[StaticLinker]
|
||||
self.targets: T.MutableMapping[str, 'Target'] = OrderedDict()
|
||||
self.run_target_names: T.Set[T.Tuple[str, str]] = set()
|
||||
self.global_args: PerMachine[T.Dict[str, T.List[str]]] = PerMachine({}, {})
|
||||
self.projects_args: PerMachine[T.Dict[str, T.List[str]]] = PerMachine({}, {})
|
||||
self.global_link_args: PerMachine[T.Dict[str, T.List[str]]] = PerMachine({}, {})
|
||||
self.projects_link_args: PerMachine[T.Dict[str, T.List[str]]] = PerMachine({}, {})
|
||||
self.tests: T.List['Test'] = []
|
||||
self.benchmarks: T.List['Test'] = []
|
||||
self.headers: T.List[Headers] = []
|
||||
self.man: T.List[Man] = []
|
||||
self.data: T.List[Data] = []
|
||||
self.static_linker: PerMachine[StaticLinker] = PerMachine(None, None)
|
||||
self.subprojects = {}
|
||||
self.subproject_dir = ''
|
||||
self.install_scripts = []
|
||||
|
@ -153,7 +200,7 @@ class Build:
|
|||
self.dep_manifest_name = None
|
||||
self.dep_manifest = {}
|
||||
self.stdlibs = PerMachine({}, {})
|
||||
self.test_setups = {} # type: T.Dict[str, TestSetup]
|
||||
self.test_setups: T.Dict[str, TestSetup] = {}
|
||||
self.test_setup_default_name = None
|
||||
self.find_overrides = {}
|
||||
self.searched_programs = set() # The list of all programs that have been searched for.
|
||||
|
@ -494,7 +541,8 @@ a hard error in the future.'''.format(name))
|
|||
class BuildTarget(Target):
|
||||
known_kwargs = known_build_target_kwargs
|
||||
|
||||
def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources, objects, environment, kwargs):
|
||||
def __init__(self, name: str, subdir: str, subproject: str, for_machine: MachineChoice,
|
||||
sources: T.List[File], objects, environment: environment.Environment, kwargs):
|
||||
super().__init__(name, subdir, subproject, True, for_machine)
|
||||
unity_opt = environment.coredata.get_builtin_option('unity')
|
||||
self.is_unity = unity_opt == 'on' or (unity_opt == 'subprojects' and subproject != '')
|
||||
|
@ -517,7 +565,7 @@ class BuildTarget(Target):
|
|||
self.outputs = [self.filename]
|
||||
self.need_install = False
|
||||
self.pch = {}
|
||||
self.extra_args = {}
|
||||
self.extra_args: T.Dict[str, T.List['FileOrString']] = {}
|
||||
self.generated = []
|
||||
self.d_features = {}
|
||||
self.pic = False
|
||||
|
@ -1239,7 +1287,7 @@ You probably should put it in link_with instead.''')
|
|||
ids = [IncludeDirs(x.get_curdir(), x.get_incdirs(), is_system, x.get_extra_build_dirs()) for x in ids]
|
||||
self.include_dirs += ids
|
||||
|
||||
def add_compiler_args(self, language, args):
|
||||
def add_compiler_args(self, language: str, args: T.List['FileOrString']) -> None:
|
||||
args = listify(args)
|
||||
for a in args:
|
||||
if not isinstance(a, (str, File)):
|
||||
|
@ -1341,9 +1389,9 @@ You probably should put it in link_with instead.''')
|
|||
m = 'Could not get a dynamic linker for build target {!r}'
|
||||
raise AssertionError(m.format(self.name))
|
||||
|
||||
def get_using_rustc(self):
|
||||
if len(self.sources) > 0 and self.sources[0].fname.endswith('.rs'):
|
||||
return True
|
||||
def get_using_rustc(self) -> bool:
|
||||
"""Is this target a rust target."""
|
||||
return self.sources and self.sources[0].fname.endswith('.rs')
|
||||
|
||||
def get_using_msvc(self):
|
||||
'''
|
||||
|
@ -1544,7 +1592,8 @@ class GeneratedList:
|
|||
class Executable(BuildTarget):
|
||||
known_kwargs = known_exe_kwargs
|
||||
|
||||
def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources, objects, environment, kwargs):
|
||||
def __init__(self, name: str, subdir: str, subproject: str, for_machine: MachineChoice,
|
||||
sources: T.List[File], objects, environment: environment.Environment, kwargs):
|
||||
self.typename = 'executable'
|
||||
if 'pie' not in kwargs and 'b_pie' in environment.coredata.base_options:
|
||||
kwargs['pie'] = environment.coredata.base_options['b_pie'].value
|
||||
|
|
|
@ -50,6 +50,11 @@ import typing as T
|
|||
|
||||
import importlib
|
||||
|
||||
if T.TYPE_CHECKING:
|
||||
from .envconfig import MachineInfo
|
||||
from .environment import Environment
|
||||
from .modules import ExtensionModule
|
||||
|
||||
permitted_method_kwargs = {
|
||||
'partial_dependency': {'compile_args', 'link_args', 'links', 'includes',
|
||||
'sources'},
|
||||
|
@ -716,34 +721,26 @@ class IncludeDirsHolder(InterpreterObject, ObjectHolder):
|
|||
InterpreterObject.__init__(self)
|
||||
ObjectHolder.__init__(self, idobj)
|
||||
|
||||
class Headers(InterpreterObject):
|
||||
class HeadersHolder(InterpreterObject, ObjectHolder):
|
||||
|
||||
def __init__(self, sources, kwargs):
|
||||
def __init__(self, obj: build.Headers):
|
||||
InterpreterObject.__init__(self)
|
||||
self.sources = sources
|
||||
self.install_subdir = kwargs.get('subdir', '')
|
||||
if os.path.isabs(self.install_subdir):
|
||||
mlog.deprecation('Subdir keyword must not be an absolute path. This will be a hard error in the next release.')
|
||||
self.custom_install_dir = kwargs.get('install_dir', None)
|
||||
self.custom_install_mode = kwargs.get('install_mode', None)
|
||||
if self.custom_install_dir is not None:
|
||||
if not isinstance(self.custom_install_dir, str):
|
||||
raise InterpreterException('Custom_install_dir must be a string.')
|
||||
ObjectHolder.__init__(self, obj)
|
||||
|
||||
def set_install_subdir(self, subdir):
|
||||
self.install_subdir = subdir
|
||||
self.held_object.install_subdir = subdir
|
||||
|
||||
def get_install_subdir(self):
|
||||
return self.install_subdir
|
||||
return self.held_object.install_subdir
|
||||
|
||||
def get_sources(self):
|
||||
return self.sources
|
||||
return self.held_object.sources
|
||||
|
||||
def get_custom_install_dir(self):
|
||||
return self.custom_install_dir
|
||||
return self.held_object.custom_install_dir
|
||||
|
||||
def get_custom_install_mode(self):
|
||||
return self.custom_install_mode
|
||||
return self.held_object.custom_install_mode
|
||||
|
||||
class DataHolder(InterpreterObject, ObjectHolder):
|
||||
def __init__(self, data):
|
||||
|
@ -771,34 +768,20 @@ class InstallDir(InterpreterObject):
|
|||
self.strip_directory = strip_directory
|
||||
self.from_source_dir = from_source_dir
|
||||
|
||||
class Man(InterpreterObject):
|
||||
class ManHolder(InterpreterObject, ObjectHolder):
|
||||
|
||||
def __init__(self, sources, kwargs):
|
||||
def __init__(self, obj: build.Man):
|
||||
InterpreterObject.__init__(self)
|
||||
self.sources = sources
|
||||
self.validate_sources()
|
||||
self.custom_install_dir = kwargs.get('install_dir', None)
|
||||
self.custom_install_mode = kwargs.get('install_mode', None)
|
||||
if self.custom_install_dir is not None and not isinstance(self.custom_install_dir, str):
|
||||
raise InterpreterException('Custom_install_dir must be a string.')
|
||||
ObjectHolder.__init__(self, obj)
|
||||
|
||||
def validate_sources(self):
|
||||
for s in self.sources:
|
||||
try:
|
||||
num = int(s.split('.')[-1])
|
||||
except (IndexError, ValueError):
|
||||
num = 0
|
||||
if num < 1 or num > 8:
|
||||
raise InvalidArguments('Man file must have a file extension of a number between 1 and 8')
|
||||
def get_custom_install_dir(self) -> T.Optional[str]:
|
||||
return self.held_object.custom_install_dir
|
||||
|
||||
def get_custom_install_dir(self):
|
||||
return self.custom_install_dir
|
||||
def get_custom_install_mode(self) -> T.Optional[FileMode]:
|
||||
return self.held_object.custom_install_mode
|
||||
|
||||
def get_custom_install_mode(self):
|
||||
return self.custom_install_mode
|
||||
|
||||
def get_sources(self):
|
||||
return self.sources
|
||||
def get_sources(self) -> T.List[mesonlib.File]:
|
||||
return self.held_object.sources
|
||||
|
||||
class GeneratedObjectsHolder(InterpreterObject, ObjectHolder):
|
||||
def __init__(self, held_object):
|
||||
|
@ -878,7 +861,7 @@ class BuildTargetHolder(TargetHolder):
|
|||
return self.held_object.name
|
||||
|
||||
class ExecutableHolder(BuildTargetHolder):
|
||||
def __init__(self, target, interp):
|
||||
def __init__(self, target: build.Executable, interp: 'Interpreter'):
|
||||
super().__init__(target, interp)
|
||||
|
||||
class StaticLibraryHolder(BuildTargetHolder):
|
||||
|
@ -1781,14 +1764,37 @@ class CompilerHolder(InterpreterObject):
|
|||
return self.compiler.get_argument_syntax()
|
||||
|
||||
|
||||
ModuleState = collections.namedtuple('ModuleState', [
|
||||
'source_root', 'build_to_src', 'subproject', 'subdir', 'current_lineno', 'environment',
|
||||
'project_name', 'project_version', 'backend', 'targets',
|
||||
'data', 'headers', 'man', 'global_args', 'project_args', 'build_machine',
|
||||
'host_machine', 'target_machine', 'current_node'])
|
||||
class ModuleState(T.NamedTuple):
|
||||
|
||||
"""Object passed to a module when it a method is called.
|
||||
|
||||
holds the current state of the meson process at a given method call in
|
||||
the interpreter.
|
||||
"""
|
||||
|
||||
source_root: str
|
||||
build_to_src: str
|
||||
subproject: str
|
||||
subdir: str
|
||||
current_lineno: str
|
||||
environment: 'Environment'
|
||||
project_name: str
|
||||
project_version: str
|
||||
backend: str
|
||||
targets: T.Dict[str, build.Target]
|
||||
data: T.List[build.Data]
|
||||
headers: T.List[build.Headers]
|
||||
man: T.List[build.Man]
|
||||
global_args: T.Dict[str, T.List[str]]
|
||||
project_args: T.Dict[str, T.List[str]]
|
||||
build_machine: 'MachineInfo'
|
||||
host_machine: 'MachineInfo'
|
||||
target_machine: 'MachineInfo'
|
||||
current_node: mparser.BaseNode
|
||||
|
||||
|
||||
class ModuleHolder(InterpreterObject, ObjectHolder):
|
||||
def __init__(self, modname, module, interpreter):
|
||||
def __init__(self, modname: str, module: 'ExtensionModule', interpreter: 'Interpreter'):
|
||||
InterpreterObject.__init__(self)
|
||||
ObjectHolder.__init__(self, module)
|
||||
self.modname = modname
|
||||
|
@ -4189,19 +4195,43 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
|
|||
@permittedKwargs(permitted_kwargs['install_headers'])
|
||||
def func_install_headers(self, node, args, kwargs):
|
||||
source_files = self.source_strings_to_files(args)
|
||||
kwargs['install_mode'] = self._get_kwarg_install_mode(kwargs)
|
||||
h = Headers(source_files, kwargs)
|
||||
install_mode = self._get_kwarg_install_mode(kwargs)
|
||||
|
||||
install_subdir = kwargs.get('subdir', '')
|
||||
if not isinstance(install_subdir, str):
|
||||
raise InterpreterException('subdir keyword argument must be a string')
|
||||
elif os.path.isabs(install_subdir):
|
||||
mlog.deprecation('Subdir keyword must not be an absolute path. This will be a hard error in the next release.')
|
||||
|
||||
install_dir = kwargs.get('install_dir', None)
|
||||
if install_dir is not None and not isinstance(install_dir, str):
|
||||
raise InterpreterException('install_dir keyword argument must be a string if provided')
|
||||
|
||||
h = build.Headers(source_files, install_subdir, install_dir, install_mode)
|
||||
self.build.headers.append(h)
|
||||
return h
|
||||
|
||||
return HeadersHolder(h)
|
||||
|
||||
@FeatureNewKwargs('install_man', '0.47.0', ['install_mode'])
|
||||
@permittedKwargs(permitted_kwargs['install_man'])
|
||||
def func_install_man(self, node, args, kwargs):
|
||||
fargs = self.source_strings_to_files(args)
|
||||
kwargs['install_mode'] = self._get_kwarg_install_mode(kwargs)
|
||||
m = Man(fargs, kwargs)
|
||||
sources = self.source_strings_to_files(args)
|
||||
for s in sources:
|
||||
try:
|
||||
num = int(s.split('.')[-1])
|
||||
except (IndexError, ValueError):
|
||||
num = 0
|
||||
if num < 1 or num > 8:
|
||||
raise InvalidArguments('Man file must have a file extension of a number between 1 and 8')
|
||||
custom_install_mode = self._get_kwarg_install_mode(kwargs)
|
||||
custom_install_dir = kwargs.get('install_dir', None)
|
||||
if custom_install_dir is not None and not isinstance(custom_install_dir, str):
|
||||
raise InterpreterException('install_dir must be a string.')
|
||||
|
||||
m = build.Man(sources, custom_install_dir, custom_install_mode)
|
||||
self.build.man.append(m)
|
||||
return m
|
||||
|
||||
return ManHolder(m)
|
||||
|
||||
@FeatureNewKwargs('subdir', '0.44.0', ['if_found'])
|
||||
@permittedKwargs(permitted_kwargs['subdir'])
|
||||
|
@ -4251,10 +4281,10 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
|
|||
pass
|
||||
self.subdir = prev_subdir
|
||||
|
||||
def _get_kwarg_install_mode(self, kwargs):
|
||||
def _get_kwarg_install_mode(self, kwargs: T.Dict[str, T.Any]) -> T.Optional[FileMode]:
|
||||
if kwargs.get('install_mode', None) is None:
|
||||
return None
|
||||
install_mode = []
|
||||
install_mode: T.List[str] = []
|
||||
mode = mesonlib.typeslistify(kwargs.get('install_mode', []), (str, int))
|
||||
for m in mode:
|
||||
# We skip any arguments that are set to `false`
|
||||
|
@ -4806,11 +4836,11 @@ Try setting b_lundef to false instead.'''.format(self.coredata.base_options['b_s
|
|||
if sproj_name != self.subproject_directory_name:
|
||||
raise InterpreterException('Sandbox violation: Tried to grab file %s from a different subproject.' % plain_filename)
|
||||
|
||||
def source_strings_to_files(self, sources):
|
||||
results = []
|
||||
def source_strings_to_files(self, sources: T.List[str]) -> T.List[mesonlib.File]:
|
||||
mesonlib.check_direntry_issues(sources)
|
||||
if not isinstance(sources, list):
|
||||
sources = [sources]
|
||||
results: T.List[mesonlib.File] = []
|
||||
for s in sources:
|
||||
if isinstance(s, (mesonlib.File, GeneratedListHolder,
|
||||
TargetHolder, CustomTargetIndexHolder,
|
||||
|
|
Loading…
Reference in New Issue