I've posted this to http://gcc.gnu.org/wiki/Cxx11AbiCompatibility. I would greatly appreciate any corrections or improvements.
On Tue, May 22, 2012 at 9:04 AM, Jeffrey Yasskin <jyass...@googlers.com> wrote: > I've put together the following description of C++98/11 ABI > (in)compatibility, so people can tell which libraries need to be > recompiled. This is useful when you've bought a library that didn't > come with source code, and you're trying to figure out if you need to > buy a new version. I think this belongs on the Wiki somewhere, but I > wanted to run it by the list first to make sure it's accurate. You can > probably skip the first section, since it's just a description of how > to use the subsequent list. > > > > This page explains how to identify when your pre-compiled library (.a > or .so) defines a symbol that has a different enough definition in > C++98 vs C++11 that it could cause runtime problems if it's linked > into a program compiled for the other version. > > First, get a list of demangled symbols from your .a or .so: > > $ (find . -name '*.a'|xargs nm -f posix; find . -name '*.so' | xargs > nm -f posix -D)|cut -f1 -d' '|LANG=C sort -u|c++filt|sort > > (There may be better ways to get this list.) > > Next, find instances in this list of the ABI changes listed below. > For example, you might find: > > std::_List_base<FooBar, std::allocator<FooBar> >::_M_clear() > > Since std::_List_base::_M_clear() destroys nodes, it's affected by the > addition of the _M_size field and can't be used by C++11 code if it > was compiled for C++98, or vice versa. If it's possible that code > outside the library would use this instance of _List_base, then you > have to recompile the library. On the other hand, if FooBar is a type > used only inside this library, then code using the library is safe. > If FooBar is defined by the library but exposed in one of the > library's headers, then the library still needs to be recompiled, > since code using it could wind up including the other version's > implementation. > > > === ABI Changes === > > complex::{real,imag}(), std::{real,imag}(complex) > > The non-const overloads go from returning _Tp& to _Tp. > [Since gcc-4.4] > > > std::list, std::_List_impl, and std::_List_base > > New _M_size member, meaning any method that adds or removes nodes or > inspects the size has a new ABI. > [Since gcc-4.7] > > > std::operator-(reverse_iterator) and std::operator-(__normal_iterator) > may return a different type if > reverse_iterator<_IteratorL>::difference_type (respectively, > __normal_iterator<_IteratorL, _Container>::difference_type) isn't > accurate. > [Since gcc-4.4] > > > map::erase(iterator), multimap::erase(iterator), > set::erase(const_iterator), set::erase(const_iterator, > const_iterator), multiset::erase(const_iterator), > multiset::erase(const_iterator, const_iterator): > > Return type changes from void to iterator. > [Since gcc-4.5] > > > _Rb_tree<T, T>::erase(const_iterator), _Rb_tree<T, > T>::erase(const_iterator, const_iterator), _Rb_tree<T, > pair>::erase(iterator): > > Return type changes from void to iterator. these are instantiated from > map and set. > [Since gcc-4.5] > > > vector::data()'s return type changes from pointer to _Tp* > > This is a no-op with most allocators, but any allocator that defines a > non-default pointer typedef will be incompatible. > [Since gcc-4.6] > > > > Probably safe: istreambuf_iterator::reference changes from _CharT& to _CharT. > > This could affect return types if they mention 'reference', but they > appear not to mention it when istreambuf_iterator is involved. > [Since gcc-4.7] > > > Probably safe: map::erase(iterator, iterator), > multimap::erase(iterator, iterator) > > C++11 uses const_iterator, which doesn't collide. Other versions of > gcc are unlikely to have defined this overload in C++98 mode, and > C++11 is unlikely to have defined the iterator version. > > [Since gcc-4.5] > > > Probably safe: Types with node allocators, like deque and tree > > C++11 uses _M_get_Node_allocator().construct(node, ...), while C++98 > uses get_allocator().construct(node->_M_value_field, ...). The node's > constructor forwards to the value_field's constructor, so this works > by default. Can this cause problems with some mix of C++98/C++11 > allocator compilations? > > > > > I haven't analyzed the debug and profile headers. > > > > > I found these differences by grepping for GXX_EXPERIMENTAL_CXX0X > inside libstdc++, and examining each instance to see if there was an > #else clause that had different behavior in C++11 vs C++98. > > > === ABI non-changes === > > libstdc++'s binary component is nearly ABI-compatible between C++98 > and C++11. Most incompatibilities are in the templates defined in > headers, but the complex<> stream operators call the real() and imag() > methods that change return type. If these calls aren't inlined, (and > they're likely to be inlined), then libstdc++ (which is compiled in > C++98 mode by default) could cause problems when linked into C++11 > programs. (http://gcc.gnu.org/PR53429) > > There have been some claims that the change in the definition of POD > types causes an ABI incompatibility, but apparently it doesn't in > practice: http://gcc.gnu.org/ml/gcc/2012-01/msg00056.html.