From d69d2697cd24bd59181916f39c4284a7679b6da4 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 5 Oct 2018 11:37:43 -0400 Subject: [PATCH 1/3] Pull out essence total map essence of MachineInfos into PerMachine We'll eventually have many other data structure duplicated for each build, host, and target machines. This sets up the infrastructure for that. --- mesonbuild/environment.py | 8 +++---- mesonbuild/mesonlib.py | 49 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index f01ba382e..fe06c36bb 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -17,7 +17,7 @@ import configparser, os, platform, re, sys, shlex, shutil, subprocess from . import coredata from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker from . import mesonlib -from .mesonlib import EnvironmentException, Popen_safe +from .mesonlib import EnvironmentException, PerMachine, Popen_safe from . import mlog from . import compilers @@ -1147,11 +1147,9 @@ class MachineInfo: literal['cpu'], literal['endian']) -class MachineInfos: +class MachineInfos(PerMachine): def __init__(self): - self.build = None - self.host = None - self.target = None + super().__init__(None, None, None) def default_missing(self): """Default host to buid and target to host. diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 33900b63f..0094a9279 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -20,6 +20,8 @@ import stat import time import platform, subprocess, operator, os, shutil, re import collections +from enum import Enum + from mesonbuild import mlog have_fcntl = False @@ -277,6 +279,53 @@ def classify_unity_sources(compilers, sources): compsrclist[comp].append(src) return compsrclist +class OrderedEnum(Enum): + """ + An Enum which additionally offers homogeneous ordered comparison. + """ + def __ge__(self, other): + if self.__class__ is other.__class__: + return self.value >= other.value + return NotImplemented + + def __gt__(self, other): + if self.__class__ is other.__class__: + return self.value > other.value + return NotImplemented + + def __le__(self, other): + if self.__class__ is other.__class__: + return self.value <= other.value + return NotImplemented + + def __lt__(self, other): + if self.__class__ is other.__class__: + return self.value < other.value + return NotImplemented + +MachineChoice = OrderedEnum('MachineChoice', ['BUILD', 'HOST', 'TARGET']) + +class PerMachine: + def __init__(self, build, host, target): + self.build = build, + self.host = host + self.target = target + + def __getitem__(self, machine: MachineChoice): + return { + MachineChoice.BUILD: self.build, + MachineChoice.HOST: self.host, + MachineChoice.TARGET: self.target + }[machine] + + def __setitem__(self, machine: MachineChoice, val): + key = { + MachineChoice.BUILD: 'build', + MachineChoice.HOST: 'host', + MachineChoice.TARGET: 'target' + }[machine] + setattr(self, key, val) + def is_osx(): return platform.system().lower() == 'darwin' From 0b1fb51b66f9cccfbd645534434df65270fba606 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 5 Oct 2018 11:39:25 -0400 Subject: [PATCH 2/3] MachineInfo: Make equality structural For existing use cases, pointer equality sufficies, but structural is much better going forward: these are intended to be immutable descriptors of the machines. --- mesonbuild/environment.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index fe06c36bb..9e010d742 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -1119,6 +1119,20 @@ class MachineInfo: self.cpu = cpu self.endian = endian + def __eq__(self, other): + if self.__class__ is not other.__class__: + return NotImplemented + return \ + self.system == other.system and \ + self.cpu_family == other.cpu_family and \ + self.cpu == other.cpu and \ + self.endian == other.endian + + def __ne__(self, other): + if self.__class__ is not other.__class__: + return NotImplemented + return not self.__eq__(other) + @staticmethod def detect(compilers = None): """Detect the machine we're running on From 68d0adf4d268e15a35a5ce706f7a31b127a7fba7 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 5 Oct 2018 11:40:45 -0400 Subject: [PATCH 3/3] Rewrite `for_*` machine checks in terms of MachineInfo and phase out It's much better to directly query the machine in question rather than do some roundabout "is_cross" thing. This is the first step for much natve- and cross- code path deduplication. --- mesonbuild/environment.py | 62 +++++++++++++++++++++++++++++++++++++++ mesonbuild/mesonlib.py | 62 ++++++++++++++++++++++++--------------- 2 files changed, 101 insertions(+), 23 deletions(-) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 9e010d742..2106c5d5d 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -1161,6 +1161,68 @@ class MachineInfo: literal['cpu'], literal['endian']) + def is_windows(self): + """ + Machine is windows? + """ + return self.system == 'windows' + + def is_cygwin(self): + """ + Machine is cygwin? + """ + return self.system == 'cygwin' + + def is_linux(self): + """ + Machine is linux? + """ + return self.system == 'linux' + + def is_darwin(self): + """ + Machine is Darwin (iOS/OS X)? + """ + return self.system in ('darwin', 'ios') + + def is_android(self): + """ + Machine is Android? + """ + return self.system == 'android' + + def is_haiku(self): + """ + Machine is Haiku? + """ + return self.system == 'haiku' + + def is_openbsd(self): + """ + Machine is OpenBSD? + """ + return self.system == 'openbsd' + + # Various prefixes and suffixes for import libraries, shared libraries, + # static libraries, and executables. + # Versioning is added to these names in the backends as-needed. + + def get_exe_suffix(self): + if self.is_windows() or self.is_cygwin(): + return 'exe' + else: + return '' + + def get_object_suffix(self): + if self.is_windows(): + return 'obj' + else: + return 'o' + + def libdir_layout_is_win(self): + return self.is_windows() \ + or self.is_cygwin() + class MachineInfos(PerMachine): def __init__(self): super().__init__(None, None, None) diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 0094a9279..ad6022fe1 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -358,77 +358,93 @@ def is_dragonflybsd(): def is_freebsd(): return platform.system().lower() == 'freebsd' +def _get_machine_is_cross(env, is_cross): + """ + This is not morally correct, but works for now. For cross builds the build + and host machines differ. `is_cross == true` means the host machine, while + `is_cross == false` means the build machine. Both are used in practice, + even though the documentation refers to the host machine implying we should + hard-code it. For non-cross builds `is_cross == false` is passed but the + host and build machines are identical so it doesn't matter. + + Users for `for_*` should instead specify up front which machine they want + and query that like: + + env.machines[MachineChoice.HOST].is_haiku() + + """ + for_machine = MachineChoice.HOST if is_cross else MachineChoice.BUILD + return env.machines[for_machine] + def for_windows(is_cross, env): """ Host machine is windows? + Deprecated: Please use `env.machines[for_machine].is_windows()`. + Note: 'host' is the machine on which compiled binaries will run """ - if not is_cross: - return is_windows() - return env.cross_info.get_host_system() == 'windows' + return _get_machine_is_cross(env, is_cross).is_windows() def for_cygwin(is_cross, env): """ Host machine is cygwin? + Deprecated: Please use `env.machines[for_machine].is_cygwin()`. + Note: 'host' is the machine on which compiled binaries will run """ - if not is_cross: - return is_cygwin() - return env.cross_info.get_host_system() == 'cygwin' + return _get_machine_is_cross(env, is_cross).is_cygwin() def for_linux(is_cross, env): """ Host machine is linux? + Deprecated: Please use `env.machines[for_machine].is_linux()`. + Note: 'host' is the machine on which compiled binaries will run """ - if not is_cross: - return is_linux() - return env.cross_info.get_host_system() == 'linux' + return _get_machine_is_cross(env, is_cross).is_linux() def for_darwin(is_cross, env): """ Host machine is Darwin (iOS/OS X)? + Deprecated: Please use `env.machines[for_machine].is_darwin()`. + Note: 'host' is the machine on which compiled binaries will run """ - if not is_cross: - return is_osx() - return env.cross_info.get_host_system() in ('darwin', 'ios') + return _get_machine_is_cross(env, is_cross).is_darwin() def for_android(is_cross, env): """ Host machine is Android? + Deprecated: Please use `env.machines[for_machine].is_android()`. + Note: 'host' is the machine on which compiled binaries will run """ - if not is_cross: - return is_android() - return env.cross_info.get_host_system() == 'android' + return _get_machine_is_cross(env, is_cross).is_android() def for_haiku(is_cross, env): """ Host machine is Haiku? + Deprecated: Please use `env.machines[for_machine].is_haiku()`. + Note: 'host' is the machine on which compiled binaries will run """ - if not is_cross: - return is_haiku() - return env.cross_info.get_host_system() == 'haiku' + return _get_machine_is_cross(env, is_cross).is_haiku() def for_openbsd(is_cross, env): """ Host machine is OpenBSD? + Deprecated: Please use `env.machines[for_machine].is_openbsd()`. + Note: 'host' is the machine on which compiled binaries will run """ - if not is_cross: - return is_openbsd() - elif env.cross_info.has_host(): - return env.cross_info.config['host_machine']['system'] == 'openbsd' - return False + return _get_machine_is_cross(env, is_cross).is_openbsd() def exe_exists(arglist): try: