diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index ceb466b62..b7a2c3037 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -315,7 +315,9 @@ class Backend(): fname = exe.fullpath else: fname = [os.path.join(self.environment.get_build_dir(), self.get_target_filename(t.get_exe()))] - is_cross = self.environment.is_cross_build() and self.environment.cross_info.need_cross_compiler() + is_cross = self.environment.is_cross_build() and \ + self.environment.cross_info.need_cross_compiler() and \ + self.environment.cross_info.need_exe_wrapper() if is_cross: exe_wrapper = self.environment.cross_info.config['binaries'].get('exe_wrapper', None) else: @@ -366,8 +368,9 @@ class Backend(): def exe_object_to_cmd_array(self, exe): if self.environment.is_cross_build() and \ - isinstance(exe, build.BuildTarget) and exe.is_cross: - if 'exe_wrapper' not in self.environment.cross_info: + 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: 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 201b2d14e..4415a68e1 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -394,9 +394,11 @@ 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.config['binaries'].get('exe_wrapper', None) is not None: - cmd += [self.environment.cross_info.config['binaries']['exe_wrapper']] + 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] cmd.append(abs_exe) else: cmd.append(target.command) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 6ff93cb5a..eae7cc018 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 os, re, subprocess +import os, re, subprocess, platform from . import coredata, mesonlib from .compilers import * import configparser @@ -52,6 +52,26 @@ def detect_ninja(): if p.returncode == 0: return n +def detect_cpu_family(): + """ + Python is inconsistent in its platform module. + It returns different values for the same cpu. + For x86 it might return 'x86', 'i686' or somesuch. + Do some canonicalization. + """ + trial = platform.machine().lower() + if trial.startswith('i') and trial.endswith('86'): + return 'x86' + if trial.startswith('arm'): + return 'arm' + if trial == 'amd64': + return 'x86_64' + # Add fixes here as bugs are reported. + return trial + +def detect_system(): + return platform.system().lower() + class Environment(): private_dir = 'meson-private' @@ -181,7 +201,10 @@ class Environment(): compilers = [self.cross_info.config['binaries']['c']] ccache = [] is_cross = True - exe_wrap = self.cross_info.config['binaries'].get('exe_wrapper', None) + if self.cross_info.need_exe_wrapper(): + exe_wrap = self.cross_info.config['binaries'].get('exe_wrapper', None) + else: + exe_wrap = [] elif evar in os.environ: compilers = os.environ[evar].split() ccache = [] @@ -239,7 +262,10 @@ class Environment(): if self.is_cross_build() and want_cross: compilers = [self.cross_info['fortran']] is_cross = True - exe_wrap = self.cross_info.get('exe_wrapper', None) + if self.cross_info.need_exe_wrapper(): + exe_wrap = self.cross_info.get('exe_wrapper', None) + else: + exe_wrap = [] elif evar in os.environ: compilers = os.environ[evar].split() is_cross = False @@ -308,7 +334,10 @@ class Environment(): compilers = [self.cross_info.config['binaries']['cpp']] ccache = [] is_cross = True - exe_wrap = self.cross_info.config['binaries'].get('exe_wrapper', None) + if self.cross_info.need_exe_wrapper(): + exe_wrap = self.cross_info.config['binaries'].get('exe_wrapper', None) + else: + exe_wrap = [] elif evar in os.environ: compilers = os.environ[evar].split() ccache = [] @@ -364,7 +393,10 @@ class Environment(): if self.is_cross_build() and want_cross: exelist = [self.cross_info['objc']] is_cross = True - exe_wrap = self.cross_info.get('exe_wrapper', None) + if self.cross_info.need_exe_wrapper(): + exe_wrap = self.cross_info.get('exe_wrapper', None) + else: + exe_wrap = [] else: exelist = self.get_objc_compiler_exelist() is_cross = False @@ -394,7 +426,10 @@ class Environment(): if self.is_cross_build() and want_cross: exelist = [self.cross_info['objcpp']] is_cross = True - exe_wrap = self.cross_info.get('exe_wrapper', None) + if self.cross_info.need_exe_wrapper(): + exe_wrap = self.cross_info.get('exe_wrapper', None) + else: + exe_wrap = [] else: exelist = self.get_objcpp_compiler_exelist() is_cross = False @@ -700,3 +735,12 @@ class CrossBuildInfo(): # But not when cross compiling a cross compiler. def need_cross_compiler(self): return 'host_machine' in self.config + + def need_exe_wrapper(self): + if self.has_host() and detect_cpu_family() == 'x86_64' and \ + self.config['host_machine']['cpu_family'] == 'x86' and \ + self.config['host_machine']['system'] == detect_system(): + # Can almost always run 32-bit binaries on 64-bit natively if the + # host and build systems are the same + return False + return True diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index d6a3a3e32..3a831cec5 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -322,24 +322,14 @@ class BuildMachine(InterpreterObject): 'endian' : self.endian_method, }) - # Python is inconsistent in its platform module. - # It returns different values for the same cpu. - # For x86 it might return 'x86', 'i686' or somesuch. - # Do some canonicalization. def cpu_family_method(self, args, kwargs): - trial = platform.machine().lower() - if trial.startswith('i') and trial.endswith('86'): - return 'x86' - if trial.startswith('arm'): - return 'arm' - # Add fixes here as bugs are reported. - return trial + return environment.detect_cpu_family() def cpu_method(self, args, kwargs): return platform.machine().lower() def system_method(self, args, kwargs): - return platform.system().lower() + return environment.detect_system() def endian_method(self, args, kwargs): return sys.byteorder @@ -883,9 +873,16 @@ class MesonMain(InterpreterObject): return self.interpreter.environment.build_dir 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: - return 'exe_wrap' in self.build.environment.cross_info.config['binaries'] - return True # This is semantically confusing. + 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_wrap', None) + if exe_wrap 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. + # Need to revisit this. + return True def is_cross_build_method(self, args, kwargs): return self.build.environment.is_cross_build()