diff options
-rw-r--r-- | mesonbuild/environment.py | 79 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 87 |
2 files changed, 98 insertions, 68 deletions
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index a0c2fda..f01ba38 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import configparser, os, platform, re, shlex, shutil, subprocess +import configparser, os, platform, re, sys, shlex, shutil, subprocess from . import coredata from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker @@ -307,13 +307,26 @@ class Environment: # Used by the regenchecker script, which runs meson self.coredata.meson_command = mesonlib.meson_command self.first_invocation = True - self.cross_info = None self.exe_wrapper = None + + self.machines = MachineInfos() + # Will be fully initialized later using compilers later. + self.machines.detect_build() if self.coredata.cross_file: self.cross_info = CrossBuildInfo(self.coredata.cross_file) if 'exe_wrapper' in self.cross_info.config['binaries']: from .dependencies import ExternalProgram self.exe_wrapper = ExternalProgram.from_cross_info(self.cross_info, 'exe_wrapper') + if 'host_machine' in self.cross_info.config: + self.machines.host = MachineInfo.from_literal( + self.cross_info.config['host_machine']) + if 'target_machine' in self.cross_info.config: + self.machines.target = MachineInfo.from_literal( + self.cross_info.config['target_machine']) + else: + self.cross_info = None + self.machines.default_missing() + self.cmd_line_options = options.cmd_line_options.copy() # List of potential compilers. @@ -1099,10 +1112,70 @@ class CrossBuildInfo: return False return True - class MachineInfo: def __init__(self, system, cpu_family, cpu, endian): self.system = system self.cpu_family = cpu_family self.cpu = cpu self.endian = endian + + @staticmethod + def detect(compilers = None): + """Detect the machine we're running on + + If compilers are not provided, we cannot know as much. None out those + fields to avoid accidentally depending on partial knowledge. The + underlying ''detect_*'' method can be called to explicitly use the + partial information. + """ + return MachineInfo( + detect_system(), + detect_cpu_family(compilers) if compilers is not None else None, + detect_cpu(compilers) if compilers is not None else None, + sys.byteorder) + + @staticmethod + def from_literal(literal): + minimum_literal = {'cpu', 'cpu_family', 'endian', 'system'} + if set(literal) < minimum_literal: + raise EnvironmentException( + 'Machine info is currently {}\n'.format(literal) + + 'but is missing {}.'.format(minimum_literal - set(literal))) + return MachineInfo( + literal['system'], + literal['cpu_family'], + literal['cpu'], + literal['endian']) + +class MachineInfos: + def __init__(self): + self.build = None + self.host = None + self.target = None + + def default_missing(self): + """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): + """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 + + def detect_build(self, compilers = None): + self.build = MachineInfo.detect(compilers) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index a4d9472..c05b92a 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -31,7 +31,7 @@ from .interpreterbase import InterpreterObject, MutableInterpreterObject, Disabl from .interpreterbase import FeatureNew, FeatureDeprecated, FeatureNewKwargs from .modules import ModuleReturnValue -import os, sys, shutil, uuid +import os, shutil, uuid import re, shlex import subprocess from collections import namedtuple @@ -573,57 +573,11 @@ class GeneratedListHolder(InterpreterObject, ObjectHolder): def add_file(self, a): self.held_object.add_file(a) -class BuildMachine(InterpreterObject, ObjectHolder): - def __init__(self, compilers): - self.compilers = compilers +# A machine that's statically known from the cross file +class MachineHolder(InterpreterObject, ObjectHolder): + def __init__(self, machine_info): InterpreterObject.__init__(self) - held_object = environment.MachineInfo(environment.detect_system(), - environment.detect_cpu_family(self.compilers), - environment.detect_cpu(self.compilers), - sys.byteorder) - ObjectHolder.__init__(self, held_object) - self.methods.update({'system': self.system_method, - 'cpu_family': self.cpu_family_method, - 'cpu': self.cpu_method, - 'endian': self.endian_method, - }) - - @noPosargs - @permittedKwargs({}) - def cpu_family_method(self, args, kwargs): - return self.held_object.cpu_family - - @noPosargs - @permittedKwargs({}) - def cpu_method(self, args, kwargs): - return self.held_object.cpu - - @noPosargs - @permittedKwargs({}) - def system_method(self, args, kwargs): - return self.held_object.system - - @noPosargs - @permittedKwargs({}) - def endian_method(self, args, kwargs): - return self.held_object.endian - -# This class will provide both host_machine and -# target_machine -class CrossMachineInfo(InterpreterObject, ObjectHolder): - def __init__(self, cross_info): - InterpreterObject.__init__(self) - minimum_cross_info = {'cpu', 'cpu_family', 'endian', 'system'} - if set(cross_info) < minimum_cross_info: - raise InterpreterException( - 'Machine info is currently {}\n'.format(cross_info) + - 'but is missing {}.'.format(minimum_cross_info - set(cross_info))) - self.info = cross_info - minfo = environment.MachineInfo(cross_info['system'], - cross_info['cpu_family'], - cross_info['cpu'], - cross_info['endian']) - ObjectHolder.__init__(self, minfo) + ObjectHolder.__init__(self, machine_info) self.methods.update({'system': self.system_method, 'cpu': self.cpu_method, 'cpu_family': self.cpu_family_method, @@ -1937,20 +1891,23 @@ class Interpreter(InterpreterBase): self.build_def_files = [os.path.join(self.subdir, environment.build_filename)] if not mock: self.parse_project() - self.builtin['build_machine'] = BuildMachine(self.coredata.compilers) - if not self.build.environment.is_cross_build(): - self.builtin['host_machine'] = self.builtin['build_machine'] - self.builtin['target_machine'] = self.builtin['build_machine'] - else: - cross_info = self.build.environment.cross_info - if cross_info.has_host(): - self.builtin['host_machine'] = CrossMachineInfo(cross_info.config['host_machine']) - else: - self.builtin['host_machine'] = self.builtin['build_machine'] - if cross_info.has_target(): - self.builtin['target_machine'] = CrossMachineInfo(cross_info.config['target_machine']) - else: - self.builtin['target_machine'] = self.builtin['host_machine'] + + # 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.machines.detect_build(self.coredata.compilers) + self.build.environment.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 + + self.builtin['build_machine'] = \ + MachineHolder(self.build.environment.machines.build) + self.builtin['host_machine'] = \ + MachineHolder(self.build.environment.machines.host) + self.builtin['target_machine'] = \ + MachineHolder(self.build.environment.machines.target) def get_non_matching_default_options(self): env = self.environment |