aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Mensinger <daniel@mensinger-ka.de>2021-06-16 23:55:06 +0200
committerDaniel Mensinger <daniel@mensinger-ka.de>2021-06-18 23:48:33 +0200
commit66b32a45915238230557d8591e4521bdd7ecdb3b (patch)
treee32a6695f079c3de1d6d51362d9044b1a90e596c
parentd601227cb2e00e8d4279f8dae27184fdbb0895e2 (diff)
downloadmeson-66b32a45915238230557d8591e4521bdd7ecdb3b.zip
meson-66b32a45915238230557d8591e4521bdd7ecdb3b.tar.gz
meson-66b32a45915238230557d8591e4521bdd7ecdb3b.tar.bz2
holders: Introduce HoldableObject
-rw-r--r--mesonbuild/build.py30
-rw-r--r--mesonbuild/compilers/compilers.py7
-rw-r--r--mesonbuild/coredata.py4
-rw-r--r--mesonbuild/dependencies/base.py4
-rw-r--r--mesonbuild/envconfig.py4
-rw-r--r--mesonbuild/interpreter/__init__.py2
-rw-r--r--mesonbuild/interpreter/interpreter.py2
-rw-r--r--mesonbuild/interpreter/interpreterobjects.py2
-rw-r--r--mesonbuild/interpreterbase/baseobjects.py34
-rw-r--r--mesonbuild/mesonlib/universal.py8
-rw-r--r--mesonbuild/programs.py2
-rwxr-xr-xrun_unittests.py21
12 files changed, 78 insertions, 42 deletions
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 8724cab7..a9abcf9 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -28,6 +28,7 @@ from . import dependencies
from . import mlog
from . import programs
from .mesonlib import (
+ HoldableObject,
File, MesonException, MachineChoice, PerMachine, OrderedSet, listify,
extract_as_list, typeslistify, stringlistify, classify_unity_sources,
get_filenames_templates_dict, substitute_values, has_path_sep, unholder,
@@ -125,13 +126,13 @@ def get_target_macos_dylib_install_name(ld) -> str:
class InvalidArguments(MesonException):
pass
-class DependencyOverride:
+class DependencyOverride(HoldableObject):
def __init__(self, dep, node, explicit=True):
self.dep = dep
self.node = node
self.explicit = explicit
-class Headers:
+class Headers(HoldableObject):
def __init__(self, sources: T.List[File], install_subdir: T.Optional[str],
install_dir: T.Optional[str], install_mode: T.Optional['FileMode'],
@@ -161,7 +162,7 @@ class Headers:
return self.custom_install_mode
-class Man:
+class Man(HoldableObject):
def __init__(self, sources: T.List[File], install_dir: T.Optional[str],
install_mode: T.Optional['FileMode'], subproject: str,
@@ -182,7 +183,7 @@ class Man:
return self.sources
-class InstallDir:
+class InstallDir(HoldableObject):
def __init__(self, src_subdir: str, inst_subdir: str, install_dir: str,
install_mode: T.Optional['FileMode'],
@@ -327,12 +328,11 @@ class Build:
return link_args.get(compiler.get_language(), [])
-class IncludeDirs:
+class IncludeDirs(HoldableObject):
"""Internal representation of an include_directories call."""
- def __init__(self, curdir: str, dirs: T.List[str], is_system: bool,
- extra_build_dirs: T.Optional[T.List[str]] = None):
+ def __init__(self, curdir: str, dirs: T.List[str], is_system: bool, extra_build_dirs: T.Optional[T.List[str]] = None):
self.curdir = curdir
self.incdirs = dirs
self.is_system = is_system
@@ -361,7 +361,7 @@ class IncludeDirs:
strlist.append(os.path.join(sourcedir, self.curdir, idir))
return strlist
-class ExtractedObjects:
+class ExtractedObjects(HoldableObject):
'''
Holds a list of sources for which the objects must be extracted
'''
@@ -416,7 +416,7 @@ class ExtractedObjects:
for source in self.srclist
]
-class EnvironmentVariables:
+class EnvironmentVariables(HoldableObject):
def __init__(self) -> None:
self.envvars = []
# The set of all env vars we have operations for. Only used for self.has_name()
@@ -458,7 +458,7 @@ class EnvironmentVariables:
env[name] = method(env, name, values, separator)
return env
-class Target:
+class Target(HoldableObject):
# TODO: should Target be an abc.ABCMeta?
@@ -1508,7 +1508,7 @@ You probably should put it in link_with instead.''')
'platforms')
return
-class Generator:
+class Generator(HoldableObject):
def __init__(self, exe: T.Union['Executable', programs.ExternalProgram],
arguments: T.List[str],
output: T.List[str],
@@ -1584,7 +1584,7 @@ class Generator:
return output
-class GeneratedList:
+class GeneratedList(HoldableObject):
"""The output of generator.process."""
@@ -2527,7 +2527,7 @@ class Jar(BuildTarget):
return ['-cp', os.pathsep.join(cp_paths)]
return []
-class CustomTargetIndex:
+class CustomTargetIndex(HoldableObject):
"""A special opaque object returned by indexing a CustomTarget. This object
exists in Meson, but acts as a proxy in the backends, making targets depend
@@ -2583,7 +2583,7 @@ class CustomTargetIndex:
def get_custom_install_dir(self):
return self.target.get_custom_install_dir()
-class ConfigurationData:
+class ConfigurationData(HoldableObject):
def __init__(self) -> None:
super().__init__()
self.values = {} # T.Dict[str, T.Union[str, int, bool]]
@@ -2602,7 +2602,7 @@ class ConfigurationData:
# A bit poorly named, but this represents plain data files to copy
# during install.
-class Data:
+class Data(HoldableObject):
def __init__(self, sources: T.List[File], install_dir: str,
install_mode: T.Optional['FileMode'], subproject: str,
rename: T.List[str] = None):
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index 19288eb..efe521c 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -23,6 +23,7 @@ from .. import coredata
from .. import mlog
from .. import mesonlib
from ..mesonlib import (
+ HoldableObject,
EnvironmentException, MachineChoice, MesonException,
Popen_safe, LibType, TemporaryDirectoryWinProof, OptionKey,
)
@@ -435,7 +436,7 @@ def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler',
class CrossNoRunException(MesonException):
pass
-class RunResult:
+class RunResult(HoldableObject):
def __init__(self, compiled: bool, returncode: int = 999,
stdout: str = 'UNDEFINED', stderr: str = 'UNDEFINED'):
self.compiled = compiled
@@ -444,7 +445,7 @@ class RunResult:
self.stderr = stderr
-class CompileResult:
+class CompileResult(HoldableObject):
"""The result of Compiler.compiles (and friends)."""
@@ -467,7 +468,7 @@ class CompileResult:
self.text_mode = text_mode
-class Compiler(metaclass=abc.ABCMeta):
+class Compiler(HoldableObject, metaclass=abc.ABCMeta):
# Libraries to ignore in find_library() since they are provided by the
# compiler or the C library. Currently only used for MSVC.
ignore_libs = [] # type: T.List[str]
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 89cec46..107e4b8 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -19,6 +19,7 @@ from itertools import chain
from pathlib import PurePath
from collections import OrderedDict
from .mesonlib import (
+ HoldableObject,
MesonException, EnvironmentException, MachineChoice, PerMachine,
PerMachineDefaultable, default_libdir, default_libexecdir,
default_prefix, split_args, OptionKey, OptionType, stringlistify,
@@ -61,7 +62,7 @@ class MesonVersionMismatchException(MesonException):
self.current_version = current_version
-class UserOption(T.Generic[_T]):
+class UserOption(T.Generic[_T], HoldableObject):
def __init__(self, description: str, choices: T.Optional[T.Union[str, T.List[_T]]], yielding: T.Optional[bool]):
super().__init__()
self.choices = choices
@@ -255,6 +256,7 @@ class UserFeatureOption(UserComboOption):
def __init__(self, description: str, value: T.Any, yielding: T.Optional[bool] = None):
super().__init__(description, self.static_choices, value, yielding)
+ self.name: T.Optional[str] = None # TODO: Refactor options to all store their name
def is_enabled(self) -> bool:
return self.value == 'enabled'
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index 515edcf..e12c697 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -22,7 +22,7 @@ from enum import Enum
from .. import mlog
from ..compilers import clib_langs
-from ..mesonlib import MachineChoice, MesonException
+from ..mesonlib import MachineChoice, MesonException, HoldableObject
from ..mesonlib import version_compare_many
from ..interpreterbase import FeatureDeprecated
@@ -65,7 +65,7 @@ class DependencyMethods(Enum):
DependencyTypeName = T.NewType('DependencyTypeName', str)
-class Dependency:
+class Dependency(HoldableObject):
@classmethod
def _process_include_type_kw(cls, kwargs: T.Dict[str, T.Any]) -> str:
diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py
index a93905a..307aac3 100644
--- a/mesonbuild/envconfig.py
+++ b/mesonbuild/envconfig.py
@@ -17,7 +17,7 @@ import typing as T
from enum import Enum
from . import mesonlib
-from .mesonlib import EnvironmentException
+from .mesonlib import EnvironmentException, HoldableObject
from . import mlog
from pathlib import Path
@@ -232,7 +232,7 @@ class Properties:
def get(self, key: str, default: T.Optional[T.Union[str, bool, int, T.List[str]]] = None) -> T.Optional[T.Union[str, bool, int, T.List[str]]]:
return self.properties.get(key, default)
-class MachineInfo:
+class MachineInfo(HoldableObject):
def __init__(self, system: str, cpu_family: str, cpu: str, endian: str):
self.system = system
self.cpu_family = cpu_family
diff --git a/mesonbuild/interpreter/__init__.py b/mesonbuild/interpreter/__init__.py
index 58ee729..62b09bf 100644
--- a/mesonbuild/interpreter/__init__.py
+++ b/mesonbuild/interpreter/__init__.py
@@ -20,6 +20,6 @@ from .interpreter import Interpreter, permitted_dependency_kwargs
from .compiler import CompilerHolder
from .interpreterobjects import (ExecutableHolder, BuildTargetHolder, CustomTargetHolder,
CustomTargetIndexHolder, MachineHolder, Test,
- ConfigurationDataHolder, SubprojectHolder, DependencyHolder,
+ ConfigurationDataObject, SubprojectHolder, DependencyHolder,
GeneratedListHolder, ExternalProgramHolder,
extract_required_kwarg)
diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py
index b4cdb57..ea36288 100644
--- a/mesonbuild/interpreter/interpreter.py
+++ b/mesonbuild/interpreter/interpreter.py
@@ -230,7 +230,7 @@ permitted_dependency_kwargs = {
'version',
}
-class Interpreter(InterpreterBase):
+class Interpreter(InterpreterBase, HoldableObject):
def __init__(
self,
diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py
index e27c1f7..db42c67 100644
--- a/mesonbuild/interpreter/interpreterobjects.py
+++ b/mesonbuild/interpreter/interpreterobjects.py
@@ -24,7 +24,7 @@ from ..interpreterbase import (ContainerTypeInfo, KwargInfo,
from ..interpreterbase.decorators import FeatureCheckBase
from ..dependencies import Dependency, ExternalLibrary, InternalDependency
from ..programs import ExternalProgram
-from ..mesonlib import FileMode, OptionKey, listify, Popen_safe
+from ..mesonlib import HoldableObject, MesonException, OptionKey, listify, Popen_safe
import typing as T
diff --git a/mesonbuild/interpreterbase/baseobjects.py b/mesonbuild/interpreterbase/baseobjects.py
index b08da2f..d910e51 100644
--- a/mesonbuild/interpreterbase/baseobjects.py
+++ b/mesonbuild/interpreterbase/baseobjects.py
@@ -15,24 +15,33 @@
from .. import mparser
from .exceptions import InvalidCode
from .helpers import flatten
+from ..mesonlib import HoldableObject
import typing as T
+if T.TYPE_CHECKING:
+ # Object holders need the actual interpreter
+ from ..interpreter import Interpreter
+
TV_fw_var = T.Union[str, int, bool, list, dict, 'InterpreterObject']
TV_fw_args = T.List[T.Union[mparser.BaseNode, TV_fw_var]]
TV_fw_kwargs = T.Dict[str, T.Union[mparser.BaseNode, TV_fw_var]]
TV_func = T.TypeVar('TV_func', bound=T.Callable[..., T.Any])
-TYPE_elementary = T.Union[str, int, bool]
-TYPE_var = T.Union[TYPE_elementary, T.List[T.Any], T.Dict[str, T.Any], 'InterpreterObject']
+TYPE_elementary = T.Union[str, int, bool, T.List[T.Any], T.Dict[str, T.Any]]
+TYPE_var = T.Union[TYPE_elementary, HoldableObject, 'MesonInterpreterObject']
TYPE_nvar = T.Union[TYPE_var, mparser.BaseNode]
+TYPE_kwargs = T.Dict[str, TYPE_var]
TYPE_nkwargs = T.Dict[str, TYPE_nvar]
TYPE_key_resolver = T.Callable[[mparser.BaseNode], str]
class InterpreterObject:
def __init__(self, *, subproject: T.Optional[str] = None) -> None:
- self.methods = {} # type: T.Dict[str, T.Callable[[T.List[TYPE_nvar], TYPE_nkwargs], TYPE_var]]
+ self.methods: T.Dict[
+ str,
+ T.Callable[[T.List[TYPE_var], TYPE_kwargs], TYPE_var]
+ ] = {}
# Current node set during a method call. This can be used as location
# when printing a warning message during a method call.
self.current_node: mparser.BaseNode = None
@@ -41,8 +50,8 @@ class InterpreterObject:
def method_call(
self,
method_name: str,
- args: TV_fw_args,
- kwargs: TV_fw_kwargs
+ args: T.List[TYPE_var],
+ kwargs: TYPE_kwargs
) -> TYPE_var:
if method_name in self.methods:
method = self.methods[method_name]
@@ -52,20 +61,23 @@ class InterpreterObject:
raise InvalidCode('Unknown method "%s" in object.' % method_name)
class MesonInterpreterObject(InterpreterObject):
- ''' All non-elementary objects should be derived from this '''
+ ''' All non-elementary objects and non-object-holders should be derived from this '''
class MutableInterpreterObject:
''' Dummy class to mark the object type as mutable '''
-TV_InterpreterObject = T.TypeVar('TV_InterpreterObject')
+InterpreterObjectTypeVar = T.TypeVar('InterpreterObjectTypeVar', bound=HoldableObject)
-class ObjectHolder(MesonInterpreterObject, T.Generic[TV_InterpreterObject]):
- def __init__(self, obj: TV_InterpreterObject, *, subproject: T.Optional[str] = None) -> None:
- super().__init__(subproject=subproject)
+class ObjectHolder(InterpreterObject, T.Generic[InterpreterObjectTypeVar]):
+ def __init__(self, obj: InterpreterObjectTypeVar, interpreter: 'Interpreter') -> None:
+ super().__init__(subproject=interpreter.subproject)
+ assert isinstance(obj, HoldableObject), f'This is a bug: Trying to hold object of type `{type(obj).__name__}` that is not an `HoldableObject`'
self.held_object = obj
+ self.interpreter = interpreter
+ self.env = self.interpreter.environment
def __repr__(self) -> str:
- return f'<Holder: {self.held_object!r}>'
+ return f'<[{type(self).__name__}] holds [{type(self.held_object).__name__}]: {self.held_object!r}>'
class RangeHolder(MesonInterpreterObject):
def __init__(self, start: int, stop: int, step: int, *, subproject: T.Optional[str] = None) -> None:
diff --git a/mesonbuild/mesonlib/universal.py b/mesonbuild/mesonlib/universal.py
index 9daabee..8dc16dc 100644
--- a/mesonbuild/mesonlib/universal.py
+++ b/mesonbuild/mesonlib/universal.py
@@ -18,6 +18,7 @@ import enum
import sys
import stat
import time
+import abc
import platform, subprocess, operator, os, shlex, shutil, re
import collections
from functools import lru_cache, wraps, total_ordering
@@ -46,6 +47,7 @@ __all__ = [
'an_unpicklable_object',
'python_command',
'project_meson_versions',
+ 'HoldableObject',
'File',
'FileMode',
'GitException',
@@ -267,6 +269,10 @@ def check_direntry_issues(direntry_array: T.Union[T.List[T.Union[str, bytes]], s
import threading
an_unpicklable_object = threading.Lock()
+class HoldableObject(metaclass=abc.ABCMeta):
+ ''' Dummy base class for all objects that can be
+ held by an interpreter.baseobjects.ObjectHolder '''
+
class FileMode:
# The first triad is for owner permissions, the second for group permissions,
# and the third for others (everyone else).
@@ -366,7 +372,7 @@ dot_C_dot_H_warning = """You are using .C or .H files in your project. This is d
Visual Studio compiler, as it treats .C files as C code, unless you add
the /TP compiler flag, but this is unreliable.
See https://github.com/mesonbuild/meson/pull/8747 for the discussions."""
-class File:
+class File(HoldableObject):
def __init__(self, is_built: bool, subdir: str, fname: str):
if fname.endswith(".C") or fname.endswith(".H"):
mlog.warning(dot_C_dot_H_warning, once=True)
diff --git a/mesonbuild/programs.py b/mesonbuild/programs.py
index 1d93b8a..06af320 100644
--- a/mesonbuild/programs.py
+++ b/mesonbuild/programs.py
@@ -30,7 +30,7 @@ if T.TYPE_CHECKING:
from .environment import Environment
-class ExternalProgram:
+class ExternalProgram(mesonlib.HoldableObject):
"""A program that is found on the system."""
diff --git a/run_unittests.py b/run_unittests.py
index f81462f..067404f 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -727,7 +727,15 @@ class InternalTests(unittest.TestCase):
self.assertEqual([1, 2, 3], listify([1, [2, [3]]]))
self.assertEqual([1, [2, [3]]], listify([1, [2, [3]]], flatten=False))
# Test flattening and unholdering
- holder1 = ObjectHolder(1)
+ class TestHeldObj(mesonbuild.mesonlib.HoldableObject):
+ def __init__(self, val: int) -> None:
+ self._val = val
+ class MockInterpreter:
+ def __init__(self) -> None:
+ self.subproject = ''
+ self.environment = None
+ heldObj1 = TestHeldObj(1)
+ holder1 = ObjectHolder(heldObj1, MockInterpreter())
self.assertEqual([holder1], listify(holder1))
self.assertEqual([holder1], listify([holder1]))
self.assertEqual([holder1, 2], listify([holder1, 2]))
@@ -753,8 +761,16 @@ class InternalTests(unittest.TestCase):
self.assertEqual([1, 2, 3], extract(kwargs, 'sources', pop=True))
self.assertEqual(kwargs, {})
+ class TestHeldObj(mesonbuild.mesonlib.HoldableObject):
+ pass
+ class MockInterpreter:
+ def __init__(self) -> None:
+ self.subproject = ''
+ self.environment = None
+ heldObj = TestHeldObj()
+
# Test unholding
- holder3 = ObjectHolder(3)
+ holder3 = ObjectHolder(heldObj, MockInterpreter())
kwargs = {'sources': [1, 2, holder3]}
self.assertEqual(kwargs, {'sources': [1, 2, holder3]})
@@ -769,7 +785,6 @@ class InternalTests(unittest.TestCase):
_mock.pcdep = mock.Mock()
_mock.pcdep.name = "some_name"
_mock.version_reqs = []
- _mock = mock.Mock(held_object=_mock)
# pkgconfig dependency as lib
deps = mesonbuild.modules.pkgconfig.DependenciesHelper(dummystate, "thislib")