Treat 32-bit compiles on 64-bit Windows as native

It's a terrible user experience to force people building 32-bit
applications on 64-bit Windows to use a cross-info file when every other
tool treats it as a 'native' compilation -- it satisfies all the
requirements for a native compile.

This commit also fixes the platform detection on Windows which would
cause the 'native cpu' to be detected as 32-bit if you installed 32-bit
Python on 64-bit Windows, or if you were building with a 32-bit
toolchain on 64-bit Windows.

Doesn't support MinGW yet -- the next commits will add that since the
changes required for that are more involved.
pull/814/head
Nirbheek Chauhan 8 years ago
parent 6590b7221e
commit ac8c8c2ba8
  1. 80
      mesonbuild/environment.py
  2. 9
      mesonbuild/interpreter.py

@ -57,26 +57,90 @@ def detect_ninja():
if p.returncode == 0 and mesonlib.version_compare(version, ">=1.6"): if p.returncode == 0 and mesonlib.version_compare(version, ">=1.6"):
return n return n
def detect_cpu_family(): def detect_native_windows_arch():
"""
The architecture of Windows itself: x86 or amd64
"""
# These env variables are always available. See:
# https://msdn.microsoft.com/en-us/library/aa384274(VS.85).aspx
# https://blogs.msdn.microsoft.com/david.wang/2006/03/27/howto-detect-process-bitness/
arch = os.environ.get('PROCESSOR_ARCHITEW6432', '').lower()
if not arch:
try:
# If this doesn't exist, something is messing with the environment
arch = os.environ['PROCESSOR_ARCHITECTURE'].lower()
except KeyError:
raise InterpreterException('Unable to detect native OS architecture')
return arch
def detect_windows_arch(compilers):
"""
Detecting the 'native' architecture of Windows is not a trivial task. We
cannot trust that the architecture that Python is built for is the 'native'
one because you can run 32-bit apps on 64-bit Windows using WOW64 and
people sometimes install 32-bit Python on 64-bit Windows.
We also can't rely on the architecture of the OS itself, since it's
perfectly normal to compile and run 32-bit applications on Windows as if
they were native applications. It's a terrible experience to require the
user to supply a cross-info file to compile 32-bit applications on 64-bit
Windows. Thankfully, the only way to compile things with Visual Studio on
Windows is by entering the 'msvc toolchain' environment, which can be
easily detected.
In the end, the sanest method is as follows:
1. Check if we're in an MSVC toolchain environment, and if so, return the
MSVC toolchain architecture as our 'native' architecture.
2. If not, check environment variables that are set by Windows and WOW64 to
find out the architecture that Windows is built for, and use that as our
'native' architecture.
"""
os_arch = detect_native_windows_arch()
if os_arch != 'amd64':
return os_arch
# If we're on 64-bit Windows, 32-bit apps can be compiled without
# cross-compilation. So if we're doing that, just set the native arch as
# 32-bit and pretend like we're running under WOW64. Else, return the
# actual Windows architecture that we deduced above.
for compiler in compilers.values():
# Check if we're using and inside an MSVC toolchain environment
if compiler.id == 'msvc' and 'VCINSTALLDIR' in os.environ:
# 'Platform' is only set when the target arch is not 'x86'.
# It's 'x64' when targetting x86_64 and 'arm' when targetting ARM.
platform = os.environ.get('Platform', 'x86').lower()
if platform == 'x86':
return platform
if compiler.id == 'gcc':
# TODO: Implement this
pass
return os_arch
def detect_cpu_family(compilers):
""" """
Python is inconsistent in its platform module. Python is inconsistent in its platform module.
It returns different values for the same cpu. It returns different values for the same cpu.
For x86 it might return 'x86', 'i686' or somesuch. For x86 it might return 'x86', 'i686' or somesuch.
Do some canonicalization. Do some canonicalization.
""" """
if mesonlib.is_windows():
trial = detect_windows_arch(compilers)
else:
trial = platform.machine().lower() trial = platform.machine().lower()
if trial.startswith('i') and trial.endswith('86'): if trial.startswith('i') and trial.endswith('86'):
return 'x86' return 'x86'
if trial.startswith('arm'): if trial.startswith('arm'):
return 'arm' return 'arm'
if trial == 'amd64': if trial in ('amd64', 'x64'):
return 'x86_64' return 'x86_64'
# Add fixes here as bugs are reported. # Add fixes here as bugs are reported.
return trial return trial
def detect_cpu(): def detect_cpu(compilers):
if mesonlib.is_windows():
trial = detect_windows_arch(compilers)
else:
trial = platform.machine().lower() trial = platform.machine().lower()
if trial == 'amd64': if trial in ('amd64', 'x64'):
return 'x86_64' return 'x86_64'
# Add fixes here as bugs are reported. # Add fixes here as bugs are reported.
return trial return trial
@ -846,10 +910,12 @@ class CrossBuildInfo():
return 'host_machine' in self.config return 'host_machine' in self.config
def need_exe_wrapper(self): def need_exe_wrapper(self):
if self.has_host() and detect_cpu_family() == 'x86_64' and \ # Can almost always run 32-bit binaries on 64-bit natively if the host
# and build systems are the same. We don't pass any compilers to
# detect_cpu_family() here because we always want to know the OS
# architecture, not what the compiler environment tells us.
if self.has_host() and detect_cpu_family({}) == 'x86_64' and \
self.config['host_machine']['cpu_family'] == 'x86' and \ self.config['host_machine']['cpu_family'] == 'x86' and \
self.config['host_machine']['system'] == detect_system(): 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 False
return True return True

@ -375,7 +375,8 @@ class GeneratedListHolder(InterpreterObject):
self.held_object.add_file(a) self.held_object.add_file(a)
class BuildMachine(InterpreterObject): class BuildMachine(InterpreterObject):
def __init__(self): def __init__(self, compilers):
self.compilers = compilers
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
self.methods.update({'system' : self.system_method, self.methods.update({'system' : self.system_method,
'cpu_family' : self.cpu_family_method, 'cpu_family' : self.cpu_family_method,
@ -384,10 +385,10 @@ class BuildMachine(InterpreterObject):
}) })
def cpu_family_method(self, args, kwargs): def cpu_family_method(self, args, kwargs):
return environment.detect_cpu_family() return environment.detect_cpu_family(self.compilers)
def cpu_method(self, args, kwargs): def cpu_method(self, args, kwargs):
return environment.detect_cpu() return environment.detect_cpu(self.compilers)
def system_method(self, args, kwargs): def system_method(self, args, kwargs):
return environment.detect_system() return environment.detect_system()
@ -1099,7 +1100,7 @@ class Interpreter():
self.variables = {} self.variables = {}
self.builtin = {} self.builtin = {}
self.parse_project() self.parse_project()
self.builtin['build_machine'] = BuildMachine() self.builtin['build_machine'] = BuildMachine(self.coredata.compilers)
if not self.build.environment.is_cross_build(): if not self.build.environment.is_cross_build():
self.builtin['host_machine'] = self.builtin['build_machine'] self.builtin['host_machine'] = self.builtin['build_machine']
self.builtin['target_machine'] = self.builtin['build_machine'] self.builtin['target_machine'] = self.builtin['build_machine']

Loading…
Cancel
Save