aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2016-09-25 10:57:49 +0530
committerNirbheek Chauhan <nirbheek@centricular.com>2016-09-26 19:48:46 +0530
commitac8c8c2ba8244714702fdc6c7ee2362c5a05c034 (patch)
treef557fe0f244ad7652e46812a1e6cba27d21342e1
parent6590b7221e1e3a30b33a6b74b380ee5a2b24d7ef (diff)
downloadmeson-ac8c8c2ba8244714702fdc6c7ee2362c5a05c034.zip
meson-ac8c8c2ba8244714702fdc6c7ee2362c5a05c034.tar.gz
meson-ac8c8c2ba8244714702fdc6c7ee2362c5a05c034.tar.bz2
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.
-rw-r--r--mesonbuild/environment.py84
-rw-r--r--mesonbuild/interpreter.py9
2 files changed, 80 insertions, 13 deletions
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 341e5e8..79c09ba 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -57,26 +57,90 @@ def detect_ninja():
if p.returncode == 0 and mesonlib.version_compare(version, ">=1.6"):
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.
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 mesonlib.is_windows():
+ trial = detect_windows_arch(compilers)
+ else:
+ trial = platform.machine().lower()
if trial.startswith('i') and trial.endswith('86'):
return 'x86'
if trial.startswith('arm'):
return 'arm'
- if trial == 'amd64':
+ if trial in ('amd64', 'x64'):
return 'x86_64'
# Add fixes here as bugs are reported.
return trial
-def detect_cpu():
- trial = platform.machine().lower()
- if trial == 'amd64':
+def detect_cpu(compilers):
+ if mesonlib.is_windows():
+ trial = detect_windows_arch(compilers)
+ else:
+ trial = platform.machine().lower()
+ if trial in ('amd64', 'x64'):
return 'x86_64'
# Add fixes here as bugs are reported.
return trial
@@ -846,10 +910,12 @@ class CrossBuildInfo():
return 'host_machine' in self.config
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']['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 0f00c5a..4412ffe 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -375,7 +375,8 @@ class GeneratedListHolder(InterpreterObject):
self.held_object.add_file(a)
class BuildMachine(InterpreterObject):
- def __init__(self):
+ def __init__(self, compilers):
+ self.compilers = compilers
InterpreterObject.__init__(self)
self.methods.update({'system' : self.system_method,
'cpu_family' : self.cpu_family_method,
@@ -384,10 +385,10 @@ class BuildMachine(InterpreterObject):
})
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):
- return environment.detect_cpu()
+ return environment.detect_cpu(self.compilers)
def system_method(self, args, kwargs):
return environment.detect_system()
@@ -1099,7 +1100,7 @@ class Interpreter():
self.variables = {}
self.builtin = {}
self.parse_project()
- self.builtin['build_machine'] = BuildMachine()
+ 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']