aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/environment.py79
-rw-r--r--mesonbuild/interpreter.py87
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