diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-29 04:41:38 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-29 04:41:38 +0000 |
commit | 7b6e527f440cd7e6f8be2b07cee320ee6ca18786 (patch) | |
tree | 4a2738d69fa2814659fdadddf5826282e73d81f4 /mesonbuild/modules/__init__.py | |
parent | Initial commit. (diff) | |
download | meson-7b6e527f440cd7e6f8be2b07cee320ee6ca18786.tar.xz meson-7b6e527f440cd7e6f8be2b07cee320ee6ca18786.zip |
Adding upstream version 1.0.1.upstream/1.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mesonbuild/modules/__init__.py')
-rw-r--r-- | mesonbuild/modules/__init__.py | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py new file mode 100644 index 0000000..b63a5da --- /dev/null +++ b/mesonbuild/modules/__init__.py @@ -0,0 +1,262 @@ +# Copyright 2019 The Meson development team + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file contains the base representation for import('modname') + +from __future__ import annotations +import dataclasses +import typing as T + +from .. import mesonlib +from ..build import IncludeDirs +from ..interpreterbase.decorators import noKwargs, noPosargs +from ..mesonlib import relpath, HoldableObject, MachineChoice +from ..programs import ExternalProgram + +if T.TYPE_CHECKING: + from .. import build + from ..interpreter import Interpreter + from ..interpreter.interpreterobjects import MachineHolder + from ..interpreterbase import TYPE_var, TYPE_kwargs + from ..programs import OverrideProgram + from ..wrap import WrapMode + from ..build import EnvironmentVariables, Executable + from ..dependencies import Dependency + +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. + """ + + def __init__(self, interpreter: 'Interpreter') -> None: + # Keep it private, it should be accessed only through methods. + self._interpreter = interpreter + + 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.root_subdir = interpreter.root_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].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 + 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 = T.cast('MachineHolder', interpreter.builtin['build_machine']).held_object + self.host_machine = T.cast('MachineHolder', interpreter.builtin['host_machine']).held_object + self.target_machine = T.cast('MachineHolder', interpreter.builtin['target_machine']).held_object + self.current_node = interpreter.current_node + + def get_include_args(self, include_dirs: T.Iterable[T.Union[str, build.IncludeDirs]], prefix: str = '-I') -> T.List[str]: + if not include_dirs: + return [] + + srcdir = self.environment.get_source_dir() + builddir = self.environment.get_build_dir() + + dirs_str: T.List[str] = [] + for dirs in include_dirs: + if isinstance(dirs, str): + dirs_str += [f'{prefix}{dirs}'] + else: + dirs_str.extend([f'{prefix}{i}' for i in dirs.to_string_list(srcdir, builddir)]) + dirs_str.extend([f'{prefix}{i}' for i in dirs.get_extra_build_dirs()]) + + return dirs_str + + def find_program(self, prog: T.Union[str, T.List[str]], required: bool = True, + version_func: T.Optional[T.Callable[['ExternalProgram'], str]] = None, + wanted: T.Optional[str] = None, silent: bool = False, + for_machine: MachineChoice = MachineChoice.HOST) -> 'ExternalProgram': + return self._interpreter.find_program_impl(prog, required=required, version_func=version_func, + wanted=wanted, silent=silent, for_machine=for_machine) + + def find_tool(self, name: str, depname: str, varname: str, required: bool = True, + wanted: T.Optional[str] = None) -> T.Union['Executable', ExternalProgram, 'OverrideProgram']: + # Look in overrides in case it's built as subproject + progobj = self._interpreter.program_from_overrides([name], []) + if progobj is not None: + return progobj + + # Look in machine file + prog_list = self.environment.lookup_binary_entry(MachineChoice.HOST, name) + if prog_list is not None: + return ExternalProgram.from_entry(name, prog_list) + + # Check if pkgconfig has a variable + dep = self.dependency(depname, native=True, required=False, wanted=wanted) + if dep.found() and dep.type_name == 'pkgconfig': + value = dep.get_variable(pkgconfig=varname) + if value: + return ExternalProgram(name, [value]) + + # Normal program lookup + return self.find_program(name, required=required, wanted=wanted) + + def dependency(self, depname: str, native: bool = False, required: bool = True, + wanted: T.Optional[str] = None) -> 'Dependency': + kwargs = {'native': native, 'required': required} + if wanted: + kwargs['version'] = wanted + # FIXME: Even if we fix the function, mypy still can't figure out what's + # going on here. And we really dont want to call interpreter + # implementations of meson functions anyway. + return self._interpreter.func_dependency(self.current_node, [depname], kwargs) # type: ignore + + def test(self, args: T.Tuple[str, T.Union[build.Executable, build.Jar, 'ExternalProgram', mesonlib.File]], + workdir: T.Optional[str] = None, + env: T.Union[T.List[str], T.Dict[str, str], str] = None, + depends: T.List[T.Union[build.CustomTarget, build.BuildTarget]] = None) -> None: + kwargs = {'workdir': workdir, + 'env': env, + 'depends': depends, + } + # typed_* takes a list, and gives a tuple to func_test. Violating that constraint + # makes the universe (or at least use of this function) implode + real_args = list(args) + # TODO: Use interpreter internal API, but we need to go through @typed_kwargs + self._interpreter.func_test(self.current_node, real_args, kwargs) + + def get_option(self, name: str, subproject: str = '', + machine: MachineChoice = MachineChoice.HOST, + lang: T.Optional[str] = None, + module: T.Optional[str] = None) -> T.Union[str, int, bool, 'WrapMode']: + return self.environment.coredata.get_option(mesonlib.OptionKey(name, subproject, machine, lang, module)) + + def is_user_defined_option(self, name: str, subproject: str = '', + machine: MachineChoice = MachineChoice.HOST, + lang: T.Optional[str] = None, + module: T.Optional[str] = None) -> bool: + key = mesonlib.OptionKey(name, subproject, machine, lang, module) + return key in self._interpreter.user_defined_options.cmd_line_options + + def process_include_dirs(self, dirs: T.Iterable[T.Union[str, IncludeDirs]]) -> T.Iterable[IncludeDirs]: + """Convert raw include directory arguments to only IncludeDirs + + :param dirs: An iterable of strings and IncludeDirs + :return: None + :yield: IncludeDirs objects + """ + for d in dirs: + if isinstance(d, IncludeDirs): + yield d + else: + yield self._interpreter.build_incdir_object([d]) + + +class ModuleObject(HoldableObject): + """Base class for all objects returned by modules + """ + def __init__(self) -> None: + self.methods: T.Dict[ + str, + T.Callable[[ModuleState, T.List['TYPE_var'], 'TYPE_kwargs'], T.Union[ModuleReturnValue, 'TYPE_var']] + ] = {} + + +class MutableModuleObject(ModuleObject): + pass + + +@dataclasses.dataclass +class ModuleInfo: + + """Metadata about a Module.""" + + name: str + added: T.Optional[str] = None + deprecated: T.Optional[str] = None + unstable: bool = False + stabilized: T.Optional[str] = None + + +class NewExtensionModule(ModuleObject): + + """Class for modern modules + + provides the found method. + """ + + INFO: ModuleInfo + + def __init__(self) -> None: + super().__init__() + self.methods.update({ + 'found': self.found_method, + }) + + @noPosargs + @noKwargs + def found_method(self, state: 'ModuleState', args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: + return self.found() + + @staticmethod + def found() -> bool: + return True + + def get_devenv(self) -> T.Optional['EnvironmentVariables']: + return None + +# FIXME: Port all modules to stop using self.interpreter and use API on +# ModuleState instead. Modules should stop using this class and instead use +# ModuleObject base class. +class ExtensionModule(NewExtensionModule): + def __init__(self, interpreter: 'Interpreter') -> None: + super().__init__() + self.interpreter = interpreter + +class NotFoundExtensionModule(NewExtensionModule): + + """Class for modern modules + + provides the found method. + """ + + def __init__(self, name: str) -> None: + super().__init__() + self.INFO = ModuleInfo(name) + + @staticmethod + def found() -> bool: + return False + + +def is_module_library(fname): + ''' + Check if the file is a library-like file generated by a module-specific + target, such as GirTarget or TypelibTarget + ''' + if hasattr(fname, 'fname'): + fname = fname.fname + suffix = fname.split('.')[-1] + return suffix in {'gir', 'typelib'} + + +class ModuleReturnValue: + def __init__(self, return_value: T.Optional['TYPE_var'], + new_objects: T.Sequence[T.Union['TYPE_var', 'build.ExecutableSerialisation']]) -> None: + self.return_value = return_value + assert isinstance(new_objects, list) + self.new_objects: T.List[T.Union['TYPE_var', 'build.ExecutableSerialisation']] = new_objects |