diff options
author | John Ericson <John.Ericson@Obsidian.Systems> | 2019-05-09 21:42:53 -0400 |
---|---|---|
committer | Jussi Pakkanen <jpakkane@gmail.com> | 2019-05-16 00:27:57 +0300 |
commit | 957d8e051c0c29beb0106e75ae7a71acc5c62cf5 (patch) | |
tree | 19bb30d1cca5db43b7f540b718a9607a23a6d96a | |
parent | 38b347ecd026b8b0f6b533392a23aeeda5221713 (diff) | |
download | meson-957d8e051c0c29beb0106e75ae7a71acc5c62cf5.zip meson-957d8e051c0c29beb0106e75ae7a71acc5c62cf5.tar.gz meson-957d8e051c0c29beb0106e75ae7a71acc5c62cf5.tar.bz2 |
Make `PerMachine` and `MachineChoice` have just `build` and `host`
Meson itself *almost* only cares about the build and host platforms. The
exception is it takes a `target_machine` in the cross file and exposes
it to the user; but it doesn't do anything else with it. It's therefore
overkill to put target in `PerMachine` and `MachineChoice`. Instead, we
make a `PerThreeMachine` only for the machine infos.
Additionally fix a few other things that were bugging me in the process:
- Get rid of `MachineInfos` class. Since `envconfig.py` was created, it
has no methods that couldn't just got on `PerMachine`
- Make `default_missing` and `miss_defaulting` work functionally. That
means we can just locally bind rather than bind as class vars the
"unfrozen" configuration. This helps prevent bugs where one forgets
to freeze a configuration.
-rw-r--r-- | mesonbuild/coredata.py | 2 | ||||
-rw-r--r-- | mesonbuild/dependencies/base.py | 8 | ||||
-rw-r--r-- | mesonbuild/envconfig.py | 36 | ||||
-rw-r--r-- | mesonbuild/environment.py | 66 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 8 | ||||
-rw-r--r-- | mesonbuild/mesonlib.py | 97 | ||||
-rwxr-xr-x | run_tests.py | 2 | ||||
-rwxr-xr-x | run_unittests.py | 2 |
8 files changed, 141 insertions, 80 deletions
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 34adad3..b8f0578 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -243,7 +243,7 @@ class CoreData: self.init_builtins() self.backend_options = {} self.user_options = {} - self.compiler_options = PerMachine({}, {}, {}) + self.compiler_options = PerMachine({}, {}) self.base_options = {} self.cross_files = self.__load_config_files(options.cross_file, 'cross') self.compilers = OrderedDict() diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 8f38d6c..034f6df 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -522,7 +522,7 @@ class ConfigToolDependency(ExternalDependency): class PkgConfigDependency(ExternalDependency): # The class's copy of the pkg-config path. Avoids having to search for it # multiple times in the same Meson invocation. - class_pkgbin = PerMachine(None, None, None) + class_pkgbin = PerMachine(None, None) # We cache all pkg-config subprocess invocations to avoid redundant calls pkgbin_cache = {} @@ -957,9 +957,9 @@ class CMakeTarget: class CMakeDependency(ExternalDependency): # The class's copy of the CMake path. Avoids having to search for it # multiple times in the same Meson invocation. - class_cmakebin = PerMachine(None, None, None) - class_cmakevers = PerMachine(None, None, None) - class_cmakeinfo = PerMachine(None, None, None) + class_cmakebin = PerMachine(None, None) + class_cmakevers = PerMachine(None, None) + class_cmakeinfo = PerMachine(None, None) # We cache all pkg-config subprocess invocations to avoid redundant calls cmake_cache = {} # Version string for the minimum CMake version diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py index 70f964e..0cdb4c4 100644 --- a/mesonbuild/envconfig.py +++ b/mesonbuild/envconfig.py @@ -16,7 +16,7 @@ import configparser, os, shlex, subprocess import typing from . import mesonlib -from .mesonlib import EnvironmentException, MachineChoice, PerMachine +from .mesonlib import EnvironmentException from . import mlog _T = typing.TypeVar('_T') @@ -255,40 +255,6 @@ class MachineInfo: def libdir_layout_is_win(self) -> bool: return self.is_windows() or self.is_cygwin() -class PerMachineDefaultable(PerMachine[typing.Optional[_T]]): - """Extends `PerMachine` with the ability to default from `None`s. - """ - def __init__(self) -> None: - super().__init__(None, None, None) - - def default_missing(self) -> None: - """Default host to buid and target to host. - - This allows just specifying nothing in the native case, just host in the - cross non-compiler case, and just target in the native-built - cross-compiler case. - """ - if self.host is None: - self.host = self.build - if self.target is None: - self.target = self.host - - def miss_defaulting(self) -> None: - """Unset definition duplicated from their previous to None - - This is the inverse of ''default_missing''. By removing defaulted - machines, we can elaborate the original and then redefault them and thus - avoid repeating the elaboration explicitly. - """ - if self.target == self.host: - self.target = None - if self.host == self.build: - self.host = None - -class MachineInfos(PerMachineDefaultable[MachineInfo]): - def matches_build_machine(self, machine: MachineChoice) -> bool: - return self.build == self[machine] - class BinaryTable(HasEnvVarFallback): def __init__( self, diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 9620639..f86b613 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -19,12 +19,13 @@ from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker, CcrxLin from . import mesonlib from .mesonlib import ( MesonException, EnvironmentException, MachineChoice, Popen_safe, + PerMachineDefaultable, PerThreeMachineDefaultable ) from . import mlog from .envconfig import ( - BinaryTable, Directories, MachineInfo, MachineInfos, MesonConfigFile, - PerMachineDefaultable, Properties, known_cpu_families, + BinaryTable, Directories, MachineInfo, MesonConfigFile, + Properties, known_cpu_families, ) from . import compilers from .compilers import ( @@ -403,48 +404,62 @@ class Environment: # Just create a fresh coredata in this case self.create_new_coredata(options) - self.machines = MachineInfos() - # Will be fully initialized later using compilers later. - self.detect_build_machine() + ## locally bind some unfrozen configuration + + # Stores machine infos, the only *three* machine one because we have a + # target machine info on for the user (Meson never cares about the + # target machine.) + machines = PerThreeMachineDefaultable() # Similar to coredata.compilers and build.compilers, but lower level in # that there is no meta data, only names/paths. - self.binaries = PerMachineDefaultable() + binaries = PerMachineDefaultable() # Misc other properties about each machine. - self.properties = PerMachineDefaultable() - - # Just uses hard-coded defaults and environment variables. Might be - # overwritten by a native file. - self.binaries.build = BinaryTable() - self.properties.build = Properties() + properties = PerMachineDefaultable() # Store paths for native and cross build files. There is no target # machine information here because nothing is installed for the target # architecture, just the build and host architectures - self.paths = PerMachineDefaultable() + paths = PerMachineDefaultable() + + ## Setup build machine defaults + + # Will be fully initialized later using compilers later. + machines.build = detect_machine_info() + + # Just uses hard-coded defaults and environment variables. Might be + # overwritten by a native file. + binaries.build = BinaryTable() + properties.build = Properties() + + ## Read in native file(s) to override build machine configuration if self.coredata.config_files is not None: config = MesonConfigFile.from_config_parser( coredata.load_configs(self.coredata.config_files)) - self.binaries.build = BinaryTable(config.get('binaries', {})) - self.paths.build = Directories(**config.get('paths', {})) + binaries.build = BinaryTable(config.get('binaries', {})) + paths.build = Directories(**config.get('paths', {})) + + ## Read in cross file(s) to override host machine configuration if self.coredata.cross_files: config = MesonConfigFile.from_config_parser( coredata.load_configs(self.coredata.cross_files)) - self.properties.host = Properties(config.get('properties', {}), False) - self.binaries.host = BinaryTable(config.get('binaries', {}), False) + properties.host = Properties(config.get('properties', {}), False) + binaries.host = BinaryTable(config.get('binaries', {}), False) if 'host_machine' in config: - self.machines.host = MachineInfo.from_literal(config['host_machine']) + machines.host = MachineInfo.from_literal(config['host_machine']) if 'target_machine' in config: - self.machines.target = MachineInfo.from_literal(config['target_machine']) - self.paths.host = Directories(**config.get('paths', {})) + machines.target = MachineInfo.from_literal(config['target_machine']) + paths.host = Directories(**config.get('paths', {})) + + ## "freeze" now initialized configuration, and "save" to the class. - self.machines.default_missing() - self.binaries.default_missing() - self.properties.default_missing() - self.paths.default_missing() + self.machines = machines.default_missing() + self.binaries = binaries.default_missing() + self.properties = properties.default_missing() + self.paths = paths.default_missing() exe_wrapper = self.binaries.host.lookup_entry('exe_wrapper') if exe_wrapper is not None: @@ -1233,9 +1248,6 @@ class Environment: self._handle_exceptions(popen_exceptions, linkers, 'linker') raise EnvironmentException('Unknown static linker "%s"' % ' '.join(linkers)) - def detect_build_machine(self, compilers = None): - self.machines.build = detect_machine_info(compilers) - def get_source_dir(self): return self.source_dir diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 1e8f972..0afbb10 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2047,12 +2047,12 @@ class Interpreter(InterpreterBase): if not mock: self.parse_project() - # Initialize machine descriptions. We can do a better job now because we + # Re-initialize machine descriptions. We can do a better job now because we # have the compilers needed to gain more knowledge, so wipe out old # inferrence and start over. - self.build.environment.machines.miss_defaulting() - self.build.environment.detect_build_machine(self.coredata.compilers) - self.build.environment.machines.default_missing() + machines = self.build.environment.machines.miss_defaulting() + machines.build = environment.detect_machine_info(self.coredata.compilers) + self.build.environment.machines = machines.default_missing() assert self.build.environment.machines.build.cpu is not None assert self.build.environment.machines.host.cpu is not None assert self.build.environment.machines.target.cpu is not None diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 07beb69..f53197b 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -313,37 +313,120 @@ class OrderedEnum(Enum): return self.value < other.value return NotImplemented + class MachineChoice(OrderedEnum): - """Enum class representing one of the three possible values for binaries, - the build, host, and target machines. + """Enum class representing one of the two abstract machine names used in + most places: the build, and host, machines. """ BUILD = 0 HOST = 1 - TARGET = 2 + class PerMachine(typing.Generic[_T]): - def __init__(self, build: _T, host: _T, target: _T): + def __init__(self, build: _T, host: _T): self.build = build self.host = host - self.target = target def __getitem__(self, machine: MachineChoice) -> _T: return { MachineChoice.BUILD: self.build, MachineChoice.HOST: self.host, - MachineChoice.TARGET: self.target }[machine] def __setitem__(self, machine: MachineChoice, val: _T) -> None: key = { MachineChoice.BUILD: 'build', MachineChoice.HOST: 'host', - MachineChoice.TARGET: 'target' }[machine] setattr(self, key, val) + def miss_defaulting(self) -> "PerMachineDefaultable[typing.Optional[_T]]": + """Unset definition duplicated from their previous to None + + This is the inverse of ''default_missing''. By removing defaulted + machines, we can elaborate the original and then redefault them and thus + avoid repeating the elaboration explicitly. + """ + unfreeze = PerMachineDefaultable() # type: PerMachineDefaultable[typing.Optional[_T]] + unfreeze.build = self.build + unfreeze.host = self.host + if unfreeze.host == unfreeze.build: + unfreeze.host = None + return unfreeze + + +class PerThreeMachine(PerMachine[_T]): + """Like `PerMachine` but includes `target` too. + + It turns out just one thing do we need track the target machine. There's no + need to computer the `target` field so we don't bother overriding the + `__getitem__`/`__setitem__` methods. + """ + def __init__(self, build: _T, host: _T, target: _T): + super().__init__(build, host) + self.target = target + + def miss_defaulting(self) -> "PerThreeMachineDefaultable[typing.Optional[_T]]": + """Unset definition duplicated from their previous to None + + This is the inverse of ''default_missing''. By removing defaulted + machines, we can elaborate the original and then redefault them and thus + avoid repeating the elaboration explicitly. + """ + unfreeze = PerThreeMachineDefaultable() # type: PerThreeMachineDefaultable[typing.Optional[_T]] + unfreeze.build = self.build + unfreeze.host = self.host + unfreeze.target = self.target + if unfreeze.target == unfreeze.host: + unfreeze.target = None + if unfreeze.host == unfreeze.build: + unfreeze.host = None + return unfreeze + + def matches_build_machine(self, machine: MachineChoice) -> bool: + return self.build == self[machine] + +class PerMachineDefaultable(PerMachine[typing.Optional[_T]]): + """Extends `PerMachine` with the ability to default from `None`s. + """ + def __init__(self) -> None: + super().__init__(None, None) + + def default_missing(self) -> "PerMachine[typing.Optional[_T]]": + """Default host to buid + + This allows just specifying nothing in the native case, and just host in the + cross non-compiler case. + """ + freeze = PerMachine(self.build, self.host) + if freeze.host is None: + freeze.host = freeze.build + return freeze + + +class PerThreeMachineDefaultable(PerMachineDefaultable, PerThreeMachine[typing.Optional[_T]]): + """Extends `PerThreeMachine` with the ability to default from `None`s. + """ + def __init__(self) -> None: + PerThreeMachine.__init__(self, None, None, None) + + def default_missing(self) -> "PerThreeMachine[typing.Optional[_T]]": + """Default host to buid and target to host. + + This allows just specifying nothing in the native case, just host in the + cross non-compiler case, and just target in the native-built + cross-compiler case. + """ + freeze = PerThreeMachine(self.build, self.host, self.target) + if freeze.host is None: + freeze.host = freeze.build + if freeze.target is None: + freeze.target = freeze.host + return freeze + + def is_sunos() -> bool: return platform.system().lower() == 'sunos' diff --git a/run_tests.py b/run_tests.py index a4b0fa2..f427736 100755 --- a/run_tests.py +++ b/run_tests.py @@ -220,7 +220,7 @@ def clear_meson_configure_class_caches(): mesonbuild.compilers.CCompiler.find_library_cache = {} mesonbuild.compilers.CCompiler.find_framework_cache = {} mesonbuild.dependencies.PkgConfigDependency.pkgbin_cache = {} - mesonbuild.dependencies.PkgConfigDependency.class_pkgbin = mesonlib.PerMachine(None, None, None) + mesonbuild.dependencies.PkgConfigDependency.class_pkgbin = mesonlib.PerMachine(None, None) def run_configure_inprocess(commandlist): old_stdout = sys.stdout diff --git a/run_unittests.py b/run_unittests.py index f4d969c..7242a5f 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -848,7 +848,7 @@ class InternalTests(unittest.TestCase): PkgConfigDependency.check_pkgconfig = old_check # Reset dependency class to ensure that in-process configure doesn't mess up PkgConfigDependency.pkgbin_cache = {} - PkgConfigDependency.class_pkgbin = PerMachine(None, None, None) + PkgConfigDependency.class_pkgbin = PerMachine(None, None) def test_version_compare(self): comparefunc = mesonbuild.mesonlib.version_compare_many |