Bug 1289946 - Work around preprocessor default defines in get_compiler_info(). r?chmanchester
Some compilers on some platforms by default #define some of the values
we're using in the source we use in get_compiler_info(). Namely,
mingw-gcc #defines WINNT by default, and the WINNT in the source is then
replaced by 1, breaking the check.
The C preprocessor, fortunately, doesn't expand macros inside C strings.
So instead of `%KERNEL WINNT`, we output `%KERNEL "WINNT"`, and strip
out the double quotes. For good measure, we do this for all values in
the source used in get_compiler_info().
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -208,29 +208,29 @@ def get_compiler_info(compiler, language
# So instead, we make things such that the version is missing when the
# clang used is below the minimum supported version (currently clang 3.6).
# We then only include the version information when the C++ compiler
# matches the feature check, so that an unsupported version of clang would
# have no version number.
check = dedent('''\
#if defined(_MSC_VER)
#if defined(__clang__)
- %COMPILER clang-cl
+ %COMPILER "clang-cl"
%VERSION _MSC_FULL_VER
#else
- %COMPILER msvc
+ %COMPILER "msvc"
%VERSION _MSC_FULL_VER
#endif
#elif defined(__clang__)
- %COMPILER clang
+ %COMPILER "clang"
# if !__cplusplus || __has_feature(cxx_alignof)
%VERSION __clang_major__.__clang_minor__.__clang_patchlevel__
# endif
#elif defined(__GNUC__)
- %COMPILER gcc
+ %COMPILER "gcc"
%VERSION __GNUC__.__GNUC_MINOR__.__GNUC_PATCHLEVEL__
#endif
#if __cplusplus
%cplusplus __cplusplus
#elif __STDC_VERSION__
%STDC_VERSION __STDC_VERSION__
#elif __STDC__
@@ -243,48 +243,48 @@ def get_compiler_info(compiler, language
# matches what we want.
for name, preprocessor_checks in (
('CPU', CPU_preprocessor_checks),
('KERNEL', kernel_preprocessor_checks),
):
for n, (value, condition) in enumerate(preprocessor_checks.iteritems()):
check += dedent('''\
#%(if)s %(condition)s
- %%%(name)s %(value)s
+ %%%(name)s "%(value)s"
''' % {
'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
+ %ENDIANNESS "little"
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
- %ENDIANNESS big
+ %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():
if line.startswith('%'):
k, _, v = line.partition(' ')
k = k.lstrip('%')
- data[k] = v.replace(' ', '')
+ data[k] = v.replace(' ', '').lstrip('"').rstrip('"')
log.debug('%s = %s', k, data[k])
try:
type = CompilerType(data['COMPILER'])
except:
raise FatalCheckError(
'Unknown compiler or compiler not supported.')
--- a/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py
@@ -113,16 +113,17 @@ GCC_PLATFORM_LINUX = {
}
GCC_PLATFORM_DARWIN = {
'__APPLE__': 1,
}
GCC_PLATFORM_WIN = {
'_WIN32': 1,
+ 'WINNT': 1,
}
GCC_PLATFORM_X86_LINUX = FakeCompiler(GCC_PLATFORM_X86, GCC_PLATFORM_LINUX)
GCC_PLATFORM_X86_64_LINUX = FakeCompiler(GCC_PLATFORM_X86_64,
GCC_PLATFORM_LINUX)
GCC_PLATFORM_ARM_LINUX = FakeCompiler(GCC_PLATFORM_ARM, GCC_PLATFORM_LINUX)
GCC_PLATFORM_X86_OSX = FakeCompiler(GCC_PLATFORM_X86, GCC_PLATFORM_DARWIN)
GCC_PLATFORM_X86_64_OSX = FakeCompiler(GCC_PLATFORM_X86_64,
--- a/python/mozbuild/mozbuild/test/configure/test_toolchain_helpers.py
+++ b/python/mozbuild/mozbuild/test/configure/test_toolchain_helpers.py
@@ -19,17 +19,21 @@ from mozunit import (
)
from mozbuild.preprocessor import Preprocessor
from mozbuild.util import ReadOnlyNamespace
from mozpack import path as mozpath
class CompilerPreprocessor(Preprocessor):
- VARSUBST = re.compile('(?P<VAR>\w+)', re.U)
+ # The C preprocessor only expands macros when they are not in C strings.
+ # For now, we don't look very hard for C strings because they don't matter
+ # that much for our unit tests, but we at least avoid expanding in the
+ # simple "FOO" case.
+ VARSUBST = re.compile('(?<!")(?P<VAR>\w+)(?!")', re.U)
NON_WHITESPACE = re.compile('\S')
HAS_FEATURE = re.compile('(__has_feature)\(([^\)]*)\)')
def __init__(self, *args, **kwargs):
Preprocessor.__init__(self, *args, **kwargs)
self.do_filter('c_substitution')
self.setMarker('#\s*')
@@ -79,23 +83,24 @@ class CompilerPreprocessor(Preprocessor)
class TestCompilerPreprocessor(unittest.TestCase):
def test_expansion(self):
pp = CompilerPreprocessor({
'A': 1,
'B': '2',
'C': 'c',
+ 'D': 'd'
})
pp.out = StringIO()
- input = StringIO('A.B.C')
+ input = StringIO('A.B.C "D"')
input.name = 'foo'
pp.do_include(input)
- self.assertEquals(pp.out.getvalue(), '1 . 2 . c')
+ self.assertEquals(pp.out.getvalue(), '1 . 2 . c "D"')
def test_condition(self):
pp = CompilerPreprocessor({
'A': 1,
'B': '2',
'C': '0L',
})
pp.out = StringIO()