Centralize description of build, host, and target, machines

Instead of just putting these together in the interpreter, put them
together in `environment.py` so Meson's implementation can also better
take advantage of them.
pull/4203/head
John Ericson 7 years ago committed by Jussi Pakkanen
parent a0e4548c41
commit 1c6b8b72cb
  1. 79
      mesonbuild/environment.py
  2. 87
      mesonbuild/interpreter.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)

@ -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

Loading…
Cancel
Save