From ba9bfd2bd84985d8915f79d2415bffe68e9deada Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Tue, 2 Mar 2021 22:17:38 -0500 Subject: Simplify module API - ModuleState is now a real class that will have methods in the future for actions modules needs, instead of using interpreter internal API. - New ModuleObject base class, similar to InterpreterObject, that should be used by all objects returned by modules. Its methods gets the ModuleState passed as first argument. It has a `methods` dictionary to define what is public API that can be called from build definition. - Method return value is not required to be a ModuleReturnValue any more, it can be any type that interpreter can holderify, including ModuleObject. - Legacy module API is maintained until we port all modules. In the future modules should be updated: - Use methods dict. - Remove snippets. - Custom objects returned by modules should all be subclass of ModuleObject to get the state iface in their methods. - Modules should never call into interpreter directly and instead state object should have wrapper API. - Stop using ModuleReturnValue in methods that just return simple objects like strings. Possibly remove ModuleReturnValue completely since all objects that needs to be processed by interpreter (e.g. CustomTarget) should be created through ModuleState API. --- mesonbuild/modules/__init__.py | 51 ++++++++++++++++++++++++++++++++----- mesonbuild/modules/fs.py | 3 ++- mesonbuild/modules/python.py | 13 +++++----- mesonbuild/modules/unstable_rust.py | 3 ++- 4 files changed, 54 insertions(+), 16 deletions(-) (limited to 'mesonbuild/modules') diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index ff27a112b..1cf7c1cf5 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -18,21 +18,58 @@ import os from .. import build -from ..mesonlib import unholder +from ..mesonlib import unholder, relpath import typing as T if T.TYPE_CHECKING: from ..interpreter import Interpreter - from ..interpreterbase import TYPE_var + from ..interpreterbase import TYPE_var, TYPE_nvar, TYPE_nkwargs + +class ModuleState: + """Object passed to all module methods. + + This is a WIP API provided to modules, it should be extended to have everything + needed so modules does not touch any other part of Meson internal APIs. + """ -class ExtensionModule: def __init__(self, interpreter: 'Interpreter') -> None: + self.source_root = interpreter.environment.get_source_dir() + self.build_to_src = relpath(interpreter.environment.get_source_dir(), + interpreter.environment.get_build_dir()) + self.subproject = interpreter.subproject + self.subdir = interpreter.subdir + 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] + # The backend object is under-used right now, but we will need it: + # https://github.com/mesonbuild/meson/issues/1419 + self.backend = interpreter.backend + self.targets = interpreter.build.targets + self.data = interpreter.build.data + self.headers = interpreter.build.get_headers() + self.man = interpreter.build.get_man() + self.global_args = interpreter.build.global_args.host + self.project_args = interpreter.build.projects_args.host.get(interpreter.subproject, {}) + self.build_machine = interpreter.builtin['build_machine'].held_object + self.host_machine = interpreter.builtin['host_machine'].held_object + self.target_machine = interpreter.builtin['target_machine'].held_object + self.current_node = interpreter.current_node + +class ModuleObject: + """Base class for all objects returned by modules + """ + def __init__(self, interpreter: T.Optional['Interpreter'] = None) -> None: + self.methods = {} # type: T.Dict[str, T.Callable[[T.List[TYPE_nvar], TYPE_nkwargs], TYPE_var]] + # FIXME: Port all modules to stop using self.interpreter and use API on + # ModuleState instead. self.interpreter = interpreter - self.snippets = set() # type: T.Set[str] # List of methods that operate only on the interpreter. - - def is_snippet(self, funcname: str) -> bool: - return funcname in self.snippets + # FIXME: Port all modules to remove snippets methods. + self.snippets: T.Set[str] = set() +# FIXME: Port all modules to use ModuleObject directly. +class ExtensionModule(ModuleObject): + pass def get_include_args(include_dirs, prefix='-I'): ''' diff --git a/mesonbuild/modules/fs.py b/mesonbuild/modules/fs.py index d0b5e978d..7de8cf7d0 100644 --- a/mesonbuild/modules/fs.py +++ b/mesonbuild/modules/fs.py @@ -29,7 +29,8 @@ from ..mesonlib import ( from ..interpreterbase import FeatureNew, typed_pos_args, noKwargs, permittedKwargs if T.TYPE_CHECKING: - from ..interpreter import Interpreter, ModuleState + from . import ModuleState + from ..interpreter import Interpreter class FSModule(ExtensionModule): diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py index 564d18143..cfe2244f1 100644 --- a/mesonbuild/modules/python.py +++ b/mesonbuild/modules/python.py @@ -21,7 +21,6 @@ from pathlib import Path from .. import mesonlib from ..mesonlib import MachineChoice, MesonException from . import ExtensionModule -from mesonbuild.modules import ModuleReturnValue from ..interpreterbase import ( noPosargs, noKwargs, permittedKwargs, InvalidArguments, @@ -399,12 +398,12 @@ class PythonInstallation(ExternalProgramHolder): else: res = os.path.join(self.platlib_install_path, subdir) - return self.interpreter.module_method_callback(ModuleReturnValue(res, [])) + return res @noPosargs @noKwargs def language_version_method(self, args, kwargs): - return self.interpreter.module_method_callback(ModuleReturnValue(self.version, [])) + return self.version @noKwargs def has_path_method(self, args, kwargs): @@ -414,7 +413,7 @@ class PythonInstallation(ExternalProgramHolder): if not isinstance(path_name, str): raise InvalidArguments('has_path argument must be a string.') - return self.interpreter.module_method_callback(ModuleReturnValue(path_name in self.paths, [])) + return path_name in self.paths @noKwargs def get_path_method(self, args, kwargs): @@ -432,7 +431,7 @@ class PythonInstallation(ExternalProgramHolder): else: raise InvalidArguments('{} is not a valid path name'.format(path_name)) - return self.interpreter.module_method_callback(ModuleReturnValue(path, [])) + return path @noKwargs def has_variable_method(self, args, kwargs): @@ -442,7 +441,7 @@ class PythonInstallation(ExternalProgramHolder): if not isinstance(var_name, str): raise InvalidArguments('has_variable argument must be a string.') - return self.interpreter.module_method_callback(ModuleReturnValue(var_name in self.variables, [])) + return var_name in self.variables @noKwargs def get_variable_method(self, args, kwargs): @@ -460,7 +459,7 @@ class PythonInstallation(ExternalProgramHolder): else: raise InvalidArguments('{} is not a valid variable name'.format(var_name)) - return self.interpreter.module_method_callback(ModuleReturnValue(var, [])) + return var @noPosargs @noKwargs diff --git a/mesonbuild/modules/unstable_rust.py b/mesonbuild/modules/unstable_rust.py index c4d7d41b6..11b436576 100644 --- a/mesonbuild/modules/unstable_rust.py +++ b/mesonbuild/modules/unstable_rust.py @@ -24,7 +24,8 @@ from ..interpreterbase import InterpreterException, permittedKwargs, FeatureNew, from ..mesonlib import stringlistify, unholder, listify, typeslistify, File if T.TYPE_CHECKING: - from ..interpreter import ModuleState, Interpreter + from . import ModuleState + from ..interpreter import Interpreter from ..dependencies import ExternalProgram -- cgit v1.2.3