aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2018-07-08 20:57:09 +0530
committerNirbheek Chauhan <nirbheek@centricular.com>2018-07-09 04:09:46 +0530
commit416a00308f5b0f228af3c93eb597eca8529fdbb0 (patch)
tree39e2576abdb4b6e79fa96d488e4413dc3af652dd
parent2093d45a4e1203d868d200628918472877c7ec31 (diff)
downloadmeson-416a00308f5b0f228af3c93eb597eca8529fdbb0.zip
meson-416a00308f5b0f228af3c93eb597eca8529fdbb0.tar.gz
meson-416a00308f5b0f228af3c93eb597eca8529fdbb0.tar.bz2
cross: Use ExternalProgram for cross-file exe_wrapper
We already have code to fetch and find binaries specified in a cross file, so use the same code for exe_wrapper. This allows us to handle the same corner-cases that were fixed for other cross binaries.
-rw-r--r--mesonbuild/backend/backends.py13
-rw-r--r--mesonbuild/backend/ninjabackend.py9
-rw-r--r--mesonbuild/compilers/c.py9
-rw-r--r--mesonbuild/dependencies/__init__.py2
-rw-r--r--mesonbuild/dependencies/base.py26
-rw-r--r--mesonbuild/environment.py19
-rw-r--r--mesonbuild/interpreter.py4
-rw-r--r--mesonbuild/mesonlib.py6
-rw-r--r--mesonbuild/mtest.py10
-rw-r--r--mesonbuild/scripts/meson_exe.py6
10 files changed, 68 insertions, 36 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 354d25a..b13aa10 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -72,6 +72,8 @@ class ExecutableSerialisation:
self.cmd_args = cmd_args
self.env = env
self.is_cross = is_cross
+ if exe_wrapper is not None:
+ assert(isinstance(exe_wrapper, dependencies.ExternalProgram))
self.exe_runner = exe_wrapper
self.workdir = workdir
self.extra_paths = extra_paths
@@ -85,6 +87,8 @@ class TestSerialisation:
self.suite = suite
self.fname = fname
self.is_cross_built = is_cross_built
+ if exe_wrapper is not None:
+ assert(isinstance(exe_wrapper, dependencies.ExternalProgram))
self.exe_runner = exe_wrapper
self.is_parallel = is_parallel
self.cmd_args = cmd_args
@@ -310,7 +314,7 @@ class Backend:
self.environment.cross_info.need_cross_compiler() and \
self.environment.cross_info.need_exe_wrapper()
if is_cross_built:
- exe_wrapper = self.environment.cross_info.config['binaries'].get('exe_wrapper', None)
+ exe_wrapper = self.environment.get_exe_wrapper()
else:
exe_wrapper = None
es = ExecutableSerialisation(basename, exe_cmd, cmd_args, env,
@@ -646,10 +650,10 @@ class Backend:
is_cross = is_cross and exe.is_cross
if isinstance(exe, dependencies.ExternalProgram):
# E.g. an external verifier or simulator program run on a generated executable.
- # Can always be run.
+ # Can always be run without a wrapper.
is_cross = False
if is_cross:
- exe_wrapper = self.environment.cross_info.config['binaries'].get('exe_wrapper', None)
+ exe_wrapper = self.environment.get_exe_wrapper()
else:
exe_wrapper = None
if mesonlib.for_windows(is_cross, self.environment) or \
@@ -711,9 +715,8 @@ class Backend:
def exe_object_to_cmd_array(self, exe):
if self.environment.is_cross_build() and \
- self.environment.cross_info.need_exe_wrapper() and \
isinstance(exe, build.BuildTarget) and exe.is_cross:
- if 'exe_wrapper' not in self.environment.cross_info.config['binaries']:
+ if self.environment.exe_wrapper is None:
s = 'Can not use target %s as a generator because it is cross-built\n'
s += 'and no exe wrapper is defined. You might want to set it to native instead.'
s = s % exe.name
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 3ee543d..f62bc67 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -595,11 +595,10 @@ int dummy;
if isinstance(texe, build.Executable):
abs_exe = os.path.join(self.environment.get_build_dir(), self.get_target_filename(texe))
deps.append(self.get_target_filename(texe))
- if self.environment.is_cross_build() and \
- self.environment.cross_info.need_exe_wrapper():
- exe_wrap = self.environment.cross_info.config['binaries'].get('exe_wrapper', None)
- if exe_wrap is not None:
- cmd += [exe_wrap]
+ if self.environment.is_cross_build():
+ exe_wrap = self.environment.get_exe_wrapper()
+ if exe_wrap:
+ cmd += exe_wrap.get_command()
cmd.append(abs_exe)
elif isinstance(texe, dependencies.ExternalProgram):
cmd += texe.get_command()
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index 8af7abc..fa6fd89 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -57,10 +57,9 @@ class CCompiler(Compiler):
self.id = 'unknown'
self.is_cross = is_cross
self.can_compile_suffixes.add('h')
- if isinstance(exe_wrapper, str):
- self.exe_wrapper = [exe_wrapper]
- else:
- self.exe_wrapper = exe_wrapper
+ self.exe_wrapper = exe_wrapper
+ if self.exe_wrapper:
+ self.exe_wrapper = self.exe_wrapper.get_command()
# Set to None until we actually need to check this
self.has_fatal_warnings_link_arg = None
@@ -278,7 +277,7 @@ class CCompiler(Compiler):
if self.exe_wrapper is None:
# Can't check if the binaries run so we have to assume they do
return
- cmdlist = self.exe_wrapper + [binary_name]
+ cmdlist = self.exe_wrapper.get_command() + [binary_name]
else:
cmdlist = [binary_name]
mlog.debug('Running test binary command: ' + ' '.join(cmdlist))
diff --git a/mesonbuild/dependencies/__init__.py b/mesonbuild/dependencies/__init__.py
index 5259c5b..00b6fa2 100644
--- a/mesonbuild/dependencies/__init__.py
+++ b/mesonbuild/dependencies/__init__.py
@@ -14,7 +14,7 @@
from .boost import BoostDependency
from .base import ( # noqa: F401
- Dependency, DependencyException, DependencyMethods, ExternalProgram, NonExistingExternalProgram,
+ Dependency, DependencyException, DependencyMethods, ExternalProgram, EmptyExternalProgram, NonExistingExternalProgram,
ExternalDependency, NotFoundDependency, ExternalLibrary, ExtraFrameworkDependency, InternalDependency,
PkgConfigDependency, find_external_dependency, get_dep_identifier, packages, _packages_accept_language)
from .dev import GMockDependency, GTestDependency, LLVMDependency, ValgrindDependency
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index 63b817a..aca5d25 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -981,10 +981,14 @@ class ExternalProgram:
def get_name(self):
return self.name
+
class NonExistingExternalProgram(ExternalProgram):
+ "A program that will never exist"
def __init__(self):
- super().__init__(name = 'nonexistingprogram', silent = True)
+ self.name = 'nonexistingprogram'
+ self.command = [None]
+ self.path = None
def __repr__(self):
r = '<{} {!r} -> {!r}>'
@@ -993,6 +997,26 @@ class NonExistingExternalProgram(ExternalProgram):
def found(self):
return False
+
+class EmptyExternalProgram(ExternalProgram):
+ '''
+ A program object that returns an empty list of commands. Used for cases
+ such as a cross file exe_wrapper to represent that it's not required.
+ '''
+
+ def __init__(self):
+ self.name = None
+ self.command = []
+ self.path = None
+
+ def __repr__(self):
+ r = '<{} {!r} -> {!r}>'
+ return r.format(self.__class__.__name__, self.name, self.command)
+
+ def found(self):
+ return True
+
+
class ExternalLibrary(ExternalDependency):
def __init__(self, name, link_args, environment, language, silent=False):
super().__init__('external', environment, language, {})
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 0aa0b32..d281712 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -309,10 +309,13 @@ 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
if self.coredata.cross_file:
self.cross_info = CrossBuildInfo(self.coredata.cross_file)
- else:
- self.cross_info = None
+ 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')
self.cmd_line_options = options.cmd_line_options.copy()
# List of potential compilers.
@@ -476,10 +479,7 @@ This is probably wrong, it should always point to the native compiler.''' % evar
# Return value has to be a list of compiler 'choices'
compilers = [compilers]
is_cross = True
- if self.cross_info.need_exe_wrapper():
- exe_wrap = self.cross_info.config['binaries'].get('exe_wrapper', None)
- else:
- exe_wrap = []
+ exe_wrap = self.get_exe_wrapper()
elif evar in os.environ:
compilers = shlex.split(os.environ[evar])
# Ensure ccache exists and remove it if it doesn't
@@ -969,6 +969,13 @@ This is probably wrong, it should always point to the native compiler.''' % evar
out = out.split('\n')[index].lstrip('libraries: =').split(':')
return [os.path.normpath(p) for p in out]
+ def get_exe_wrapper(self):
+ if not self.cross_info.need_exe_wrapper():
+ from .dependencies import EmptyExternalProgram
+ return EmptyExternalProgram()
+ return self.exe_wrapper
+
+
class CrossBuildInfo:
def __init__(self, filename):
self.config = {'properties': {}}
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 833e982..4368ffb 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1668,10 +1668,8 @@ class MesonMain(InterpreterObject):
@permittedKwargs({})
def has_exe_wrapper_method(self, args, kwargs):
if self.is_cross_build_method(None, None) and \
- 'binaries' in self.build.environment.cross_info.config and \
self.build.environment.cross_info.need_exe_wrapper():
- exe_wrap = self.build.environment.cross_info.config['binaries'].get('exe_wrapper', None)
- if exe_wrap is None:
+ if self.build.environment.exe_wrapper is None:
return False
# We return True when exe_wrap is defined, when it's not needed, and
# when we're compiling natively. The last two are semantically confusing.
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index efb8d11..4a60452 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -1057,6 +1057,12 @@ def detect_subprojects(spdir_name, current_dir='', result=None):
def get_error_location_string(fname, lineno):
return '{}:{}:'.format(fname, lineno)
+def substring_is_in_list(substr, strlist):
+ for s in strlist:
+ if substr in s:
+ return True
+ return False
+
class OrderedSet(collections.MutableSet):
"""A set that preserves the order in which items are added, by first
insertion.
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py
index 855154f..3c4073b 100644
--- a/mesonbuild/mtest.py
+++ b/mesonbuild/mtest.py
@@ -241,6 +241,7 @@ class SingleTestRunner:
return None
else:
return [self.test.exe_runner] + self.test.fname
+ return self.test.exe_runner.get_command() + self.test.fname
else:
return self.test.fname
@@ -257,19 +258,12 @@ class SingleTestRunner:
self.test.timeout = None
return self._run_cmd(wrap + cmd + self.test.cmd_args + self.options.test_args)
- @staticmethod
- def _substring_in_list(substr, strlist):
- for s in strlist:
- if substr in s:
- return True
- return False
-
def _run_cmd(self, cmd):
starttime = time.time()
if len(self.test.extra_paths) > 0:
self.env['PATH'] = os.pathsep.join(self.test.extra_paths + ['']) + self.env['PATH']
- if self._substring_in_list('wine', cmd):
+ if mesonlib.substring_is_in_list('wine', cmd):
wine_paths = ['Z:' + p for p in self.test.extra_paths]
wine_path = ';'.join(wine_paths)
# Don't accidentally end with an `;` because that will add the
diff --git a/mesonbuild/scripts/meson_exe.py b/mesonbuild/scripts/meson_exe.py
index a70acca..ee5906b 100644
--- a/mesonbuild/scripts/meson_exe.py
+++ b/mesonbuild/scripts/meson_exe.py
@@ -19,6 +19,8 @@ import pickle
import platform
import subprocess
+from .. import mesonlib
+
options = None
def buildparser():
@@ -49,7 +51,7 @@ def run_exe(exe):
if exe.exe_runner is None:
raise AssertionError('BUG: Trying to run cross-compiled exes with no wrapper')
else:
- cmd = [exe.exe_runner] + exe.fname
+ cmd = exe.exe_runner.get_command() + exe.fname
else:
cmd = exe.fname
child_env = os.environ.copy()
@@ -57,7 +59,7 @@ def run_exe(exe):
if len(exe.extra_paths) > 0:
child_env['PATH'] = (os.pathsep.join(exe.extra_paths + ['']) +
child_env['PATH'])
- if exe.exe_runner and 'wine' in exe.exe_runner:
+ if exe.exe_runner and mesonlib.substring_is_in_list('wine', exe.exe_runner.get_command()):
wine_paths = ['Z:' + p for p in exe.extra_paths]
wine_path = ';'.join(wine_paths)
# Don't accidentally end with an `;` because that will add the