Bug 1264482 - Move adding -std=gnu99 and -std=gnu++11 to moz.configure. r=ted
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 06 Apr 2016 17:18:07 +0900
changeset 331691 a1a03c58109d5bfc8e86d8ce49c883409817d791
parent 331690 3abd062e590cf38b1addb1fd3a24fe38a5cc7d6d
child 331692 7bffe558f364bea04f7e3eea847cc05e12d3e0ab
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs1264482
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1264482 - Move adding -std=gnu99 and -std=gnu++11 to moz.configure. r=ted We were unconditionally adding them, now actually check what the compilers default to and add the flags if they are necessary. This will, in the future, allow finer grained policy changes, where we can decide that C++11 and C++14 are fine, downgrading compilers that do C++17, etc.
build/autoconf/toolchain.m4
build/moz.configure/toolchain.configure
js/src/old-configure.in
old-configure.in
--- 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,39 +186,119 @@ 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.configure.constants', _import='CompilerType')
 @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
+    '''
+    # 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:
+        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(' ', '')
+            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.
@@ -337,17 +417,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.
@@ -373,27 +453,30 @@ def compiler(language, host_or_target, c
                     % quote(os.path.dirname(full_path)))
             if os.path.normcase(find_program(compiler)) != os.path.normcase(
                     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
-            return namespace(
-                wrapper=wrapper,
-                compiler=compiler,
-                flags=flags,
-                type=type,
-                version=version,
-            )
-        die('Failed to get the compiler version')
+        type, version, more_flags = check_compiler(
+            wrapper + [compiler] + flags, language)
+        return namespace(
+            wrapper=wrapper,
+            compiler=compiler,
+            flags=flags + more_flags,
+            type=type,
+            version=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,
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -710,18 +710,16 @@ MOZ_ARG_ENABLE_BOOL(warnings-as-errors,
                           Enable treating warnings as errors],
     MOZ_ENABLE_WARNINGS_AS_ERRORS=1,
     MOZ_ENABLE_WARNINGS_AS_ERRORS=)
 
 dnl ========================================================
 dnl GNU specific defaults
 dnl ========================================================
 if test "$GNU_CC"; then
-    # We use C99.
-    CFLAGS="$CFLAGS -std=gnu99"
     MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(DSO_SONAME) -o $@'
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(DSO_SONAME) -o $@'
     DSO_LDOPTS='-shared'
     if test "$GCC_USE_GNU_LD"; then
         # Some tools like ASan use a runtime library that is only
         # linked against executables, so we must allow undefined
         # symbols for shared objects in some cases.
         if test -z "$MOZ_NO_WLZDEFS"; then
--- a/old-configure.in
+++ b/old-configure.in
@@ -895,18 +895,16 @@ MOZ_ARG_ENABLE_BOOL(warnings-as-errors,
 
 dnl ========================================================
 dnl GNU specific defaults
 dnl ========================================================
 if test "$GNU_CC"; then
     MMX_FLAGS="-mmmx"
     SSE_FLAGS="-msse"
     SSE2_FLAGS="-msse2"
-    # We use C99.
-    CFLAGS="$CFLAGS -std=gnu99"
     # FIXME: Let us build with strict aliasing. bug 414641.
     CFLAGS="$CFLAGS -fno-strict-aliasing"
     MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(DSO_SONAME) -o $@'
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(DSO_SONAME) -o $@'
     WARNINGS_AS_ERRORS='-Werror'
     DSO_CFLAGS=''
     DSO_PIC_CFLAGS='-fPIC'
     ASFLAGS="$ASFLAGS -fPIC"