Bug 657653. Check for libstdc++ versions in stdc++compat.cpp; r=ted,glandium
authorRafael Ávila de Espíndola <respindola@mozilla.com>
Wed, 08 Jun 2011 22:35:24 -0400
changeset 70816 685f5ae6e7debc49f3f1baee24887e88a9b87a30
parent 70815 eff4d5de06f4d89960c04b5b7ad82e9b0bb15b97
child 70817 63c8f645cc1c254e32ff935a4fcfc3e8820d0a79
push idunknown
push userunknown
push dateunknown
reviewersted, glandium
bugs657653
milestone7.0a1
Bug 657653. Check for libstdc++ versions in stdc++compat.cpp; r=ted,glandium
build/autoconf/libstdcxx.py
build/stdc++compat.cpp
config/autoconf.mk.in
config/rules.mk
configure.in
js/src/config/rules.mk
new file mode 100755
--- /dev/null
+++ b/build/autoconf/libstdcxx.py
@@ -0,0 +1,73 @@
+#!/usr/bin/python
+
+# This script find the version of libstdc++ and prints it as single number
+# with 8 bits per element. For example, GLIBCXX_3.4.10 becomes
+# 3 << 16 | 4 << 8 | 10 = 197642. This format is easy to use
+# in the C preprocessor.
+
+# We find out both the host and target versions. Since the output
+# will be used from shell, we just print the two assignments and evaluate
+# them from shell.
+
+import os
+import subprocess
+import re
+
+re_for_ld = re.compile('.*\((.*)\).*')
+
+def parse_readelf_line(x):
+    """Return the version from a readelf line that looks like:
+    0x00ec: Rev: 1  Flags: none  Index: 8  Cnt: 2  Name: GLIBCXX_3.4.6
+    """
+    return x.split(':')[-1].split('_')[-1].strip()
+
+def parse_ld_line(x):
+    """Parse a line from the output of ld -t. The output of gold is just
+    the full path, gnu ld prints "-lstdc++ (path)".
+    """
+    t = re_for_ld.match(x)
+    if t:
+        return t.groups()[0].strip()
+    return x.strip()
+
+def split_ver(v):
+    """Covert the string '1.2.3' into the list [1,2,3]
+    """
+    return [int(x) for x in v.split('.')]
+
+def cmp_ver(a, b):
+    """Compare versions in the form 'a.b.c'
+    """
+    for (i, j) in zip(split_ver(a), split_ver(b)):
+        if i != j:
+            return i - j
+    return 0
+
+def encode_ver(v):
+    """Encode the version as a single number.
+    """
+    t = split_ver(v)
+    return t[0] << 16 | t[1] << 8 | t[2]
+
+def find_version(e):
+    """Given the value of environment variable CXX or HOST_CXX, find the
+    version of the libstdc++ it uses.
+    """
+    args = e.split()
+    args +=  ['-shared', '-Wl,-t']
+    p = subprocess.Popen(args, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+    candidates = [x for x in p.stdout if 'libstdc++.so' in x]
+    assert len(candidates) == 1
+    libstdcxx = parse_ld_line(candidates[-1])
+
+    p = subprocess.Popen(['readelf', '-V', libstdcxx], stdout=subprocess.PIPE)
+    versions = [parse_readelf_line(x)
+                for x in p.stdout.readlines() if 'Name: GLIBCXX' in x]
+    last_version = sorted(versions, cmp = cmp_ver)[-1]
+    return encode_ver(last_version)
+
+if __name__ == '__main__':
+    cxx_env = os.environ['CXX']
+    print 'MOZ_LIBSTDCXX_TARGET_VERSION=%s' % find_version(cxx_env)
+    host_cxx_env = os.environ.get('HOST_CXX', cxx_env)
+    print 'MOZ_LIBSTDCXX_HOST_VERSION=%s' % find_version(host_cxx_env)
--- a/build/stdc++compat.cpp
+++ b/build/stdc++compat.cpp
@@ -36,27 +36,40 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include <ostream>
 #include <istream>
 #ifdef DEBUG
 #include <string>
 #endif
 
+
+/* GLIBCXX_3.4.8  is from gcc 4.1.1 (111691)
+   GLIBCXX_3.4.9  is from gcc 4.2.0 (111690)
+   GLIBCXX_3.4.10 is from gcc 4.3.0 (126287)
+   GLIBCXX_3.4.11 is from gcc 4.4.0 (133006)
+   GLIBCXX_3.4.12 is from gcc 4.4.1 (147138)
+   GLIBCXX_3.4.13 is from gcc 4.4.2 (151127)
+   GLIBCXX_3.4.14 is from gcc 4.5.0 (151126)
+   GLIBCXX_3.4.15 is from gcc 4.6.0 (160071)
+   GLIBCXX_3.4.16 is form gcc 4.6.1 (172240) */
+
+#define GLIBCXX_VERSION(a, b, c) (((a) << 16) | ((b) << 8) | (c))
+
 namespace std {
-#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)
+#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 9)
     /* Instantiate these templates to avoid GLIBCXX_3.4.9 symbol versions */
     template ostream& ostream::_M_insert(double);
     template ostream& ostream::_M_insert(long);
     template ostream& ostream::_M_insert(unsigned long);
     template ostream& __ostream_insert(ostream&, const char*, streamsize);
     template istream& istream::_M_extract(double&);
 #endif
 #ifdef DEBUG
-#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)
+#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 14)
     /* Instantiate these templates to avoid GLIBCXX_3.4.14 symbol versions
      * in debug builds */
     template char *string::_S_construct_aux_2(size_type, char, allocator<char> const&);
 #ifdef _GLIBCXX_USE_WCHAR_T
     template wchar_t *wstring::_S_construct_aux_2(size_type, wchar_t, allocator<wchar_t> const&);
 #endif /* _GLIBCXX_USE_WCHAR_T */
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
     template string::basic_string(string&&);
@@ -65,45 +78,45 @@ namespace std {
     template wstring& wstring::operator=(wstring&&);
     template wstring& wstring::assign(wstring&&);
 #endif /* __GXX_EXPERIMENTAL_CXX0X__ */
 #endif /* (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5) */
 #endif /* DEBUG */
 }
 
 namespace std __attribute__((visibility("default"))) {
-#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)
+#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 14)
     /* Hack to avoid GLIBCXX_3.4.14 symbol versions */
     struct _List_node_base
     {
         void hook(_List_node_base * const __position) throw ();
 
         void unhook() throw ();
 
         void transfer(_List_node_base * const __first,
                       _List_node_base * const __last) throw();
 
 /* Hack to avoid GLIBCXX_3.4.15 symbol versions */
-#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)
+#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 15)
         static void swap(_List_node_base& __x, _List_node_base& __y) throw ();
     };
 
     namespace __detail {
 
     struct _List_node_base
     {
 #endif
         void _M_hook(_List_node_base * const __position) throw ();
 
         void _M_unhook() throw ();
 
         void _M_transfer(_List_node_base * const __first,
                          _List_node_base * const __last) throw();
 
-#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)
+#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 15)
         static void swap(_List_node_base& __x, _List_node_base& __y) throw ();
 #endif
     };
 
     /* The functions actually have the same implementation */
     void
     _List_node_base::_M_hook(_List_node_base * const __position) throw ()
     {
@@ -119,29 +132,29 @@ namespace std __attribute__((visibility(
     void
     _List_node_base::_M_transfer(_List_node_base * const __first,
                                  _List_node_base * const __last) throw ()
     {
         ((std::_List_node_base *)this)->transfer((std::_List_node_base * const)__first,
                                                  (std::_List_node_base * const)__last);
     }
 
-#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)
+#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 15)
     void
     _List_node_base::swap(_List_node_base& __x, _List_node_base& __y) throw ()
     {
         std::_List_node_base::swap(*((std::_List_node_base *) &__x),
                                    *((std::_List_node_base *) &__y));
     }
 }
 #endif
 
-#endif /* (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5) */
+#endif /*MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 14)*/
 
-#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)
+#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 11)
     /* Hack to avoid GLIBCXX_3.4.11 symbol versions
        An inline definition of ctype<char>::_M_widen_init() used to be in
        locale_facets.h before GCC 4.4, but moved out of headers in more
        recent versions.
        It is actually safe to make it do nothing. */
     void ctype<char>::_M_widen_init() const {}
 #endif
 
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -115,16 +115,18 @@ MOZ_VTUNE       = @MOZ_VTUNE@
 MOZ_TRACE_JSCALLS = @MOZ_TRACE_JSCALLS@
 MOZ_TRACEVIS    = @MOZ_TRACEVIS@
 DEHYDRA_PATH    = @DEHYDRA_PATH@
 
 NS_TRACE_MALLOC = @NS_TRACE_MALLOC@
 USE_ELF_DYNSTR_GC = @USE_ELF_DYNSTR_GC@
 USE_ELF_HACK = @USE_ELF_HACK@
 STDCXX_COMPAT = @STDCXX_COMPAT@
+MOZ_LIBSTDCXX_TARGET_VERSION=@MOZ_LIBSTDCXX_TARGET_VERSION@
+MOZ_LIBSTDCXX_HOST_VERSION=@MOZ_LIBSTDCXX_HOST_VERSION@
 INCREMENTAL_LINKER = @INCREMENTAL_LINKER@
 MACOSX_DEPLOYMENT_TARGET = @MACOSX_DEPLOYMENT_TARGET@
 MOZ_MAIL_NEWS	= @MOZ_MAIL_NEWS@
 ENABLE_TESTS	= @ENABLE_TESTS@
 IBMBIDI = @IBMBIDI@
 MOZ_UNIVERSALCHARDET = @MOZ_UNIVERSALCHARDET@
 ACCESSIBILITY = @ACCESSIBILITY@
 MOZ_BRANDING_DIRECTORY = @MOZ_BRANDING_DIRECTORY@
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -902,16 +902,19 @@ ifdef SHARED_LIBRARY
 endif
 endif # SHARED_LIBRARY || PROGRAM
 endif # WINNT_
 endif # MOZ_PROFILE_GENERATE || MOZ_PROFILE_USE
 endif # NO_PROFILE_GUIDED_OPTIMIZE
 
 ##############################################
 
+stdc++compat.$(OBJ_SUFFIX): CXXFLAGS+=-DMOZ_LIBSTDCXX_VERSION=$(MOZ_LIBSTDCXX_TARGET_VERSION)
+host_stdc++compat.$(OBJ_SUFFIX): CXXFLAGS+=-DMOZ_LIBSTDCXX_VERSION=$(MOZ_LIBSTDCXX_HOST_VERSION)
+
 checkout:
 	$(MAKE) -C $(topsrcdir) -f client.mk checkout
 
 clean clobber realclean clobber_all:: $(SUBMAKEFILES)
 	-$(RM) $(ALL_TRASH)
 	-$(RM) -r $(ALL_TRASH_DIRS)
 	$(foreach dir,$(PARALLEL_DIRS) $(DIRS) $(STATIC_DIRS) $(TOOL_DIRS),-$(call SUBMAKE,$@,$(dir)))
 
--- a/configure.in
+++ b/configure.in
@@ -7660,16 +7660,22 @@ dnl ====================================
 
 STDCXX_COMPAT=
 MOZ_ARG_ENABLE_BOOL(stdcxx-compat,
 [  --enable-stdcxx-compat  Enable compatibility with older libstdc++],
     STDCXX_COMPAT=stdc++compat.cpp)
 
 AC_SUBST(STDCXX_COMPAT)
 
+if test -n "$STDCXX_COMPAT"; then
+   eval $($_topsrcdir/build/autoconf/libstdcxx.py)
+   AC_SUBST(MOZ_LIBSTDCXX_TARGET_VERSION)
+   AC_SUBST(MOZ_LIBSTDCXX_HOST_VERSION)
+fi
+
 dnl ========================================================
 dnl = 
 dnl = Profiling and Instrumenting
 dnl = 
 dnl ========================================================
 MOZ_ARG_HEADER(Profiling and Instrumenting)
 
 dnl ========================================================
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -902,16 +902,19 @@ ifdef SHARED_LIBRARY
 endif
 endif # SHARED_LIBRARY || PROGRAM
 endif # WINNT_
 endif # MOZ_PROFILE_GENERATE || MOZ_PROFILE_USE
 endif # NO_PROFILE_GUIDED_OPTIMIZE
 
 ##############################################
 
+stdc++compat.$(OBJ_SUFFIX): CXXFLAGS+=-DMOZ_LIBSTDCXX_VERSION=$(MOZ_LIBSTDCXX_TARGET_VERSION)
+host_stdc++compat.$(OBJ_SUFFIX): CXXFLAGS+=-DMOZ_LIBSTDCXX_VERSION=$(MOZ_LIBSTDCXX_HOST_VERSION)
+
 checkout:
 	$(MAKE) -C $(topsrcdir) -f client.mk checkout
 
 clean clobber realclean clobber_all:: $(SUBMAKEFILES)
 	-$(RM) $(ALL_TRASH)
 	-$(RM) -r $(ALL_TRASH_DIRS)
 	$(foreach dir,$(PARALLEL_DIRS) $(DIRS) $(STATIC_DIRS) $(TOOL_DIRS),-$(call SUBMAKE,$@,$(dir)))