diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index c1a36546c..8c6c60ecd 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 @@ -1130,6 +1130,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 @@ -1167,11 +1181,71 @@ class MachineInfo: literal['cpu'], endian) -class MachineInfos: + 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): - 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 dfd468746..04228a82c 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' @@ -309,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: