--- a/build/autoconf/toolchain.m4
+++ b/build/autoconf/toolchain.m4
@@ -135,19 +135,16 @@ PATH=$_SAVE_PATH
])
AC_DEFUN([MOZ_CXX11],
[
dnl Updates to the test below should be duplicated further below for the
dnl cross-compiling case.
AC_LANG_CPLUSPLUS
if test "$GNU_CXX"; then
- CXXFLAGS="$CXXFLAGS -std=gnu++11"
- _ADDED_CXXFLAGS="-std=gnu++11"
-
if test -n "$CLANG_CC"; then
dnl We'd normally just check for the version from CC_VERSION (fed
dnl from __clang_major__ and __clang_minor__), but the clang that
dnl comes with Xcode has a completely different version scheme
dnl despite exposing the version with the same defines.
dnl So instead of a version check, do a feature check. Normally,
dnl we'd use __has_feature, but there are unfortunately no C++11
dnl differences in clang 3.4. However, it supports the 2013-08-28
@@ -196,30 +193,26 @@ if test -n "$CROSS_COMPILE"; then
changequote([,])
if test "$HOST_GCC_MAJOR_VERSION" -eq 4 -a "$HOST_GCC_MINOR_VERSION" -lt 8 ||
test "$HOST_GCC_MAJOR_VERSION" -lt 4; then
AC_MSG_ERROR([Only GCC 4.8 or newer supported for host compiler])
fi
fi
- HOST_CXXFLAGS="$HOST_CXXFLAGS -std=gnu++11"
-
_SAVE_CXXFLAGS="$CXXFLAGS"
_SAVE_CPPFLAGS="$CPPFLAGS"
_SAVE_CXX="$CXX"
CXXFLAGS="$HOST_CXXFLAGS"
CPPFLAGS="$HOST_CPPFLAGS"
CXX="$HOST_CXX"
if test "$HOST_CC_TYPE" = clang; then
AC_TRY_COMPILE([], [#if !__cpp_static_assert
#error ISO WG21 SG10 feature test macros unsupported
#endif],,AC_MSG_ERROR([Only clang/llvm 3.4 or newer supported]))
fi
CXXFLAGS="$_SAVE_CXXFLAGS"
CPPFLAGS="$_SAVE_CPPFLAGS"
CXX="$_SAVE_CXX"
-elif test "$GNU_CXX"; then
- HOST_CXXFLAGS="$HOST_CXXFLAGS $_ADDED_CXXFLAGS"
fi
AC_LANG_C
])
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -186,42 +186,121 @@ def try_preprocess(compiler, language, s
with LineIO(lambda l: log.debug('| %s', l)) as o:
o.write(out)
finally:
os.remove(path)
@imports(_from='mozbuild.util', _import='LimitedString')
@imports(_from='textwrap', _import='dedent')
-def check_compiler(compiler, language):
+def get_compiler_info(compiler, language):
+ '''Returns information about the given `compiler` (command line in the
+ form of a list or tuple), in the given `language`.
+
+ The returned information includes:
+ - the compiler type (msvc, clang-cl, clang or gcc)
+ - the compiler version
+ - the compiler supported language
+ - the compiler supported language version
+ '''
class CompilerType(LimitedString):
POSSIBLE_VALUES = ('msvc', 'clang-cl', 'clang', 'gcc')
+ # Note: MSVC doesn't expose __STDC_VERSION__. It does expose __STDC__,
+ # but only when given the -Za option, which disables compiler
+ # extensions.
check = dedent('''\
#if defined(_MSC_VER)
#if defined(__clang__)
- COMPILER clang-cl _MSC_VER
+ %COMPILER clang-cl
+ %VERSION _MSC_VER
#else
- COMPILER msvc _MSC_FULL_VER
+ %COMPILER msvc
+ %VERSION _MSC_FULL_VER
#endif
#elif defined(__clang__)
- COMPILER clang __clang_major__.__clang_minor__.__clang_patchlevel__
+ %COMPILER clang
+ %VERSION __clang_major__.__clang_minor__.__clang_patchlevel__
#elif defined(__GNUC__)
- COMPILER gcc __GNUC__.__GNUC_MINOR__.__GNUC_PATCHLEVEL__
+ %COMPILER gcc
+ %VERSION __GNUC__.__GNUC_MINOR__.__GNUC_PATCHLEVEL__
+ #endif
+
+ #if __cplusplus
+ %cplusplus __cplusplus
+ #elif __STDC_VERSION__
+ %STDC_VERSION __STDC_VERSION__
+ #elif __STDC__
+ %STDC_VERSION 198900L
#endif
''')
result = try_preprocess(compiler, language, check)
- if result:
- for line in result.splitlines():
- if line.startswith('COMPILER '):
- _, type, version = line.split(None, 2)
- version = version.replace(' ', '')
- return CompilerType(type), version
+ if not result:
+ return
+
+ data = {}
+ for line in result.splitlines():
+ if line.startswith('%') and ' ' in line:
+ k, v = line.split(' ', 1)
+ k = k.lstrip('%')
+ data[k] = v.replace(' ', '')
+ log.debug('%s = %s', k, data[k])
+
+ type = data.get('COMPILER')
+ if not type:
+ raise FatalCheckError(
+ 'Unknown compiler or compiler not supported.')
+
+ cplusplus = int(data.get('cplusplus', '0L').rstrip('L'))
+ stdc_version = int(data.get('STDC_VERSION', '0L').rstrip('L'))
+
+ return namespace(
+ type=CompilerType(type),
+ version=data['VERSION'],
+ 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):
+ info = get_compiler_info(compiler, language)
+
+ flags = []
+
+ def append_flag(flag):
+ if flag not in flags:
+ if info.type == 'clang-cl':
+ flags.append('-Xclang')
+ flags.append(flag)
+
+ # Check language standards
+ # --------------------------------------------------------------------
+ if language != info.language:
+ raise FatalCheckError(
+ '`%s` is not a %s compiler.' % (quote(*compiler), language))
+
+ # Note: We do a strict version check because there sometimes are backwards
+ # incompatible changes in the standard, and not all code that compiles as
+ # C99 compiles as e.g. C11 (as of writing, this is true of libnestegg, for
+ # example)
+ if info.language == 'C' and info.language_version != 199901:
+ if info.type in ('clang-cl', 'clang', 'gcc'):
+ append_flag('-std=gnu99')
+
+ # Note: MSVC, while supporting C++11, still reports 199711L for __cplusplus.
+ # Note: this is a strict version check because we used to always add
+ # -std=gnu++11.
+ if info.language == 'C++' and info.language_version != 201103:
+ if info.type in ('clang-cl', 'clang', 'gcc'):
+ append_flag('-std=gnu++11')
+
+ return info.type, info.version, flags
@template
def default_c_compilers(host_or_target):
'''Template defining the set of default C compilers for the host and
target platforms.
`host_or_target` is either `host` or `target` (the @depends functions
from init.configure.
@@ -340,17 +419,17 @@ def compiler(language, host_or_target, c
# Normally, we'd use `var` instead of `_var`, but the interaction with
# old-configure complicates things, and for now, we a) can't take the plain
# result from check_prog as CC/CXX/HOST_CC/HOST_CXX and b) have to let
# old-configure AC_SUBST it (because it's autoconf doing it, not us)
compiler = check_prog('_%s' % var, what=what, progs=default_compilers,
input=delayed_getattr(provided_compiler, 'compiler'))
@depends(compiler, provided_compiler, compiler_wrapper)
- @checking('%s version' % what, lambda x: x.version if x else 'not found')
+ @checking('whether %s can be used' % what, lambda x: bool(x))
@imports(_from='mozbuild.shellutil', _import='quote')
def valid_compiler(compiler, provided_compiler, compiler_wrapper):
wrapper = list(compiler_wrapper or ())
if provided_compiler:
provided_wrapper = list(provided_compiler.wrapper)
# When doing a subconfigure, the compiler is set by old-configure
# and it contains the wrappers from --with-compiler-wrapper and
# --with-ccache.
@@ -378,26 +457,31 @@ def compiler(language, host_or_target, c
full_path):
die('Found `%s` before `%s` in your $PATH. '
'Please reorder your $PATH.',
quote(os.path.dirname(found_compiler)),
quote(os.path.dirname(full_path)))
result = check_compiler(wrapper + [compiler] + flags, language)
if result:
- type, version = result
+ type, version, more_flags = result
return namespace(
wrapper=wrapper,
compiler=compiler,
- flags=flags,
+ flags=flags + more_flags,
type=type,
version=version,
)
die('Failed to get the compiler version')
+ @depends(valid_compiler)
+ @checking('%s version' % what)
+ def compiler_version(compiler):
+ return compiler.version
+
if language == 'C++':
@depends(valid_compiler, c_compiler)
def compiler_suite_consistency(compiler, c_compiler):
if compiler.type != c_compiler.type:
die('The %s C compiler is %s, while the %s C++ compiler is '
'%s. Need to use the same compiler suite.',
host_or_target_str, c_compiler.type,
host_or_target_str, compiler.type)