Bug 1288313 - Ensure the host and target compilers build for the right endianness. r?chmanchester draft
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 21 Jul 2016 08:24:45 +0900
changeset 390440 ad64c13c0e57bdb1a0aa18e95df1d7e7d7bee958
parent 390439 877197a941a2fa5e3520ff22b4b3dcbe7dee1058
child 525999 2eacbfa3b9388561f1afef2b314b9e59f2ef4746
push id23669
push userbmo:mh+mozilla@glandium.org
push dateThu, 21 Jul 2016 04:54:31 +0000
reviewerschmanchester
bugs1288313
milestone50.0a1
Bug 1288313 - Ensure the host and target compilers build for the right endianness. r?chmanchester
build/moz.configure/init.configure
build/moz.configure/toolchain.configure
python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -400,20 +400,20 @@ def split_triplet(triplet):
     elif cpu.startswith('sparc') or cpu == 'sun4u':
         canonical_cpu = 'sparc'
         endianness = 'big'
     elif cpu.startswith('arm'):
         canonical_cpu = 'arm'
         endianness = 'big' if cpu.startswith(('armeb', 'armbe')) else 'little'
     elif cpu in ('mips', 'mipsel'):
         canonical_cpu = 'mips32'
-        endianness = 'little' if 'le' in cpu else 'big'
+        endianness = 'little' if 'el' in cpu else 'big'
     elif cpu in ('mips64', 'mips64el'):
         canonical_cpu = 'mips64'
-        endianness = 'little' if 'le' in cpu else 'big'
+        endianness = 'little' if 'el' in cpu else 'big'
     elif cpu.startswith('aarch64'):
         canonical_cpu = 'aarch64'
         endianness = 'little'
     else:
         die('Unknown CPU type: %s' % cpu)
 
     return namespace(
         alias=triplet,
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -267,16 +267,27 @@ def get_compiler_info(compiler, language
             ''' % {
                 'if': 'elif' if n else 'if',
                 'condition': condition,
                 'name': name,
                 'value': value,
             })
         check += '#endif\n'
 
+    # Also check for endianness. The advantage of living in modern times is
+    # that all the modern compilers we support now have __BYTE_ORDER__ defined
+    # by the preprocessor, except MSVC, which only supports little endian.
+    check += dedent('''\
+        #if _MSC_VER || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+        %ENDIANNESS little
+        #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+        %ENDIANNESS big
+        #endif
+    ''')
+
     result = try_preprocess(compiler, language, check)
 
     if not result:
         raise FatalCheckError(
             'Unknown compiler or compiler not supported.')
 
     data = {}
     for line in result.splitlines():
@@ -307,16 +318,17 @@ def get_compiler_info(compiler, language
     if version:
         version = Version(version)
 
     return namespace(
         type=type,
         version=version,
         cpu=data.get('CPU'),
         kernel=data.get('KERNEL'),
+        endianness=data.get('ENDIANNESS'),
         language='C++' if cplusplus else 'C',
         language_version=cplusplus if cplusplus else stdc_version,
     )
 
 
 @imports(_from='mozbuild.shellutil', _import='quote')
 def check_compiler(compiler, language, target):
     info = get_compiler_info(compiler, language)
@@ -373,21 +385,26 @@ def check_compiler(compiler, language, t
                 append_flag('-m32')
             elif (info.cpu, target.cpu) in same_arch_different_bits:
                 append_flag('-m64')
 
     if not info.kernel or info.kernel != target.kernel:
         if info.type == 'clang':
             append_flag('--target=%s' % target.toolchain)
 
+    if not info.endianness or info.endianness != target.endianness:
+        if info.type == 'clang':
+            append_flag('--target=%s' % target.toolchain)
+
     return namespace(
         type=info.type,
         version=info.version,
         target_cpu=info.cpu,
         target_kernel=info.kernel,
+        target_endianness=info.endianness,
         flags=flags,
     )
 
 
 @template
 def default_c_compilers(host_or_target):
     '''Template defining the set of default C compilers for the host and
     target platforms.
@@ -588,16 +605,25 @@ def compiler(language, host_or_target, c
         if not info.target_kernel or (info.target_kernel !=
                                       host_or_target.kernel):
             raise FatalCheckError(
                 '%s %s compiler target kernel (%s) does not match --%s kernel (%s)'
                 % (host_or_target_str.capitalize(), language,
                    info.target_kernel or 'unknown', host_or_target_str,
                    host_or_target.kernel))
 
+        if not info.target_endianness or (info.target_endianness !=
+                                          host_or_target.endianness):
+            raise FatalCheckError(
+                '%s %s compiler target endianness (%s) does not match --%s '
+                'endianness (%s)'
+                % (host_or_target_str.capitalize(), language,
+                   info.target_endianness or 'unknown', host_or_target_str,
+                   host_or_target.endianness))
+
         if info.flags:
             raise FatalCheckError(
                 'Unknown compiler or compiler not supported.')
 
         # Compiler version checks
         # ===================================================
         # Check the compiler version here instead of in `compiler_version` so
         # that the `checking` message doesn't pretend the compiler can be used
--- a/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py
@@ -49,16 +49,18 @@ SUPPORTS_GNUXX11 = {
 @memoize
 def GCC_BASE(version):
     version = Version(version)
     return FakeCompiler({
         '__GNUC__': version.major,
         '__GNUC_MINOR__': version.minor,
         '__GNUC_PATCHLEVEL__': version.patch,
         '__STDC__': 1,
+        '__ORDER_LITTLE_ENDIAN__': 1234,
+        '__ORDER_BIG_ENDIAN__': 4321,
     })
 
 
 @memoize
 def GCC(version):
     return GCC_BASE(version) + SUPPORTS_GNU99
 
 
@@ -69,37 +71,45 @@ def GXX(version):
 
 GCC_4_7 = GCC('4.7.3')
 GXX_4_7 = GXX('4.7.3')
 GCC_4_9 = GCC('4.9.3')
 GXX_4_9 = GXX('4.9.3')
 GCC_5 = GCC('5.2.1') + DEFAULT_C11
 GXX_5 = GXX('5.2.1')
 
-GCC_PLATFORM_X86 = {
+GCC_PLATFORM_LITTLE_ENDIAN = {
+    '__BYTE_ORDER__': 1234,
+}
+
+GCC_PLATFORM_BIG_ENDIAN = {
+    '__BYTE_ORDER__': 4321,
+}
+
+GCC_PLATFORM_X86 = FakeCompiler(GCC_PLATFORM_LITTLE_ENDIAN) + {
     None: {
         '__i386__': 1,
     },
     '-m64': {
         '__i386__': False,
         '__x86_64__': 1,
     },
 }
 
-GCC_PLATFORM_X86_64 = {
+GCC_PLATFORM_X86_64 = FakeCompiler(GCC_PLATFORM_LITTLE_ENDIAN) + {
     None: {
         '__x86_64__': 1,
     },
     '-m32': {
         '__x86_64__': False,
         '__i386__': 1,
     },
 }
 
-GCC_PLATFORM_ARM = {
+GCC_PLATFORM_ARM = FakeCompiler(GCC_PLATFORM_LITTLE_ENDIAN) + {
     '__arm__': 1,
 }
 
 GCC_PLATFORM_LINUX = {
     '__linux__': 1,
 }
 
 GCC_PLATFORM_DARWIN = {
@@ -914,82 +924,93 @@ class LinuxCrossCompileToolchainTest(Bas
     ARM_GXX_5_RESULT = LinuxToolchainTest.GXX_5_RESULT + {
         'compiler': '/usr/bin/arm-linux-gnu-g++-5',
     }
     CLANG_3_6_RESULT = LinuxToolchainTest.CLANG_3_6_RESULT
     CLANGXX_3_6_RESULT = LinuxToolchainTest.CLANGXX_3_6_RESULT
     GCC_4_9_RESULT = LinuxToolchainTest.GCC_4_9_RESULT
     GXX_4_9_RESULT = LinuxToolchainTest.GXX_4_9_RESULT
 
+    little_endian = FakeCompiler(GCC_PLATFORM_LINUX,
+                                 GCC_PLATFORM_LITTLE_ENDIAN)
+    big_endian = FakeCompiler(GCC_PLATFORM_LINUX, GCC_PLATFORM_BIG_ENDIAN)
+
     PLATFORMS = {
         'i686-pc-linux-gnu': GCC_PLATFORM_X86_LINUX,
         'x86_64-pc-linux-gnu': GCC_PLATFORM_X86_64_LINUX,
         'arm-unknown-linux-gnu': GCC_PLATFORM_ARM_LINUX,
-        'aarch64-unknown-linux-gnu': FakeCompiler(GCC_PLATFORM_LINUX) + {
+        'aarch64-unknown-linux-gnu': little_endian + {
             '__aarch64__': 1,
         },
-        'ia64-unknown-linux-gnu': FakeCompiler(GCC_PLATFORM_LINUX) + {
+        'ia64-unknown-linux-gnu': little_endian + {
             '__ia64__': 1,
         },
-        's390x-unknown-linux-gnu': FakeCompiler(GCC_PLATFORM_LINUX) + {
+        's390x-unknown-linux-gnu': big_endian + {
             '__s390x__': 1,
             '__s390__': 1,
         },
-        's390-unknown-linux-gnu': FakeCompiler(GCC_PLATFORM_LINUX) + {
+        's390-unknown-linux-gnu': big_endian + {
             '__s390__': 1,
         },
-        'powerpc64-unknown-linux-gnu': FakeCompiler(GCC_PLATFORM_LINUX) + {
+        'powerpc64-unknown-linux-gnu': big_endian + {
             None: {
                 '__powerpc64__': 1,
                 '__powerpc__': 1,
             },
             '-m32': {
                 '__powerpc64__': False,
             },
         },
-        'powerpc-unknown-linux-gnu': FakeCompiler(GCC_PLATFORM_LINUX) + {
+        'powerpc-unknown-linux-gnu': big_endian + {
             None: {
                 '__powerpc__': 1,
             },
             '-m64': {
                 '__powerpc64__': 1,
             },
         },
-        'alpha-unknown-linux-gnu': FakeCompiler(GCC_PLATFORM_LINUX) + {
+        'alpha-unknown-linux-gnu': little_endian + {
             '__alpha__': 1,
         },
-        'hppa-unknown-linux-gnu': FakeCompiler(GCC_PLATFORM_LINUX) + {
+        'hppa-unknown-linux-gnu': big_endian + {
             '__hppa__': 1,
         },
-        'sparc64-unknown-linux-gnu': FakeCompiler(GCC_PLATFORM_LINUX) + {
+        'sparc64-unknown-linux-gnu': big_endian + {
             None: {
                 '__arch64__': 1,
                 '__sparc__': 1,
             },
             '-m32': {
                 '__arch64__': False,
             },
         },
-        'sparc-unknown-linux-gnu': FakeCompiler(GCC_PLATFORM_LINUX) + {
+        'sparc-unknown-linux-gnu': big_endian + {
             None: {
                 '__sparc__': 1,
             },
             '-m64': {
                 '__arch64__': 1,
             },
         },
-        'mips64-unknown-linux-gnuabi64': FakeCompiler(GCC_PLATFORM_LINUX) + {
+        'mips64-unknown-linux-gnuabi64': big_endian + {
             '__mips64': 1,
             '__mips__': 1,
         },
-        'mips-unknown-linux-gnu': FakeCompiler(GCC_PLATFORM_LINUX) + {
+        'mips-unknown-linux-gnu': big_endian + {
             '__mips__': 1,
         },
     }
 
+    PLATFORMS['powerpc64le-unknown-linux-gnu'] = \
+        PLATFORMS['powerpc64-unknown-linux-gnu'] + GCC_PLATFORM_LITTLE_ENDIAN
+    PLATFORMS['mips64el-unknown-linux-gnuabi64'] = \
+        PLATFORMS['mips64-unknown-linux-gnuabi64'] + GCC_PLATFORM_LITTLE_ENDIAN
+    PLATFORMS['mipsel-unknown-linux-gnu'] = \
+        PLATFORMS['mips-unknown-linux-gnu'] + GCC_PLATFORM_LITTLE_ENDIAN
+
     def do_test_cross_gcc_32_64(self, host, target):
         self.HOST = host
         self.TARGET = target
         paths = {
             '/usr/bin/gcc': GCC_4_9 + self.PLATFORMS[host],
             '/usr/bin/g++': GXX_4_9 + self.PLATFORMS[host],
         }
         cross_flags = {
@@ -1055,16 +1076,29 @@ class LinuxCrossCompileToolchainTest(Bas
         self.HOST = LinuxCrossCompileToolchainTest.HOST
         self.TARGET = LinuxCrossCompileToolchainTest.TARGET
 
     def test_cross_gcc_misc(self):
         for target in self.PLATFORMS:
             if not target.endswith('-pc-linux-gnu'):
                 self.do_test_cross_gcc('x86_64-pc-linux-gnu', target)
 
+    def test_cannot_cross(self):
+        self.TARGET = 'mipsel-unknown-linux-gnu'
+
+        paths = {
+            '/usr/bin/gcc': GCC_4_9 + self.PLATFORMS['mips-unknown-linux-gnu'],
+            '/usr/bin/g++': GXX_4_9 + self.PLATFORMS['mips-unknown-linux-gnu'],
+        }
+        self.do_toolchain_test(paths, {
+            'c_compiler': ('Target C compiler target endianness (big) '
+                           'does not match --target endianness (little)'),
+        })
+        self.TARGET = LinuxCrossCompileToolchainTest.TARGET
+
     def test_overridden_cross_gcc(self):
         self.do_toolchain_test(self.PATHS, {
             'c_compiler': self.ARM_GCC_5_RESULT,
             'cxx_compiler': self.ARM_GXX_5_RESULT,
             'host_c_compiler': self.GCC_4_9_RESULT,
             'host_cxx_compiler': self.GXX_4_9_RESULT,
         }, environ={
             'CC': 'arm-linux-gnu-gcc-5',