[cfe-dev] May libc++ support symbol versioning?

David Chisnall via cfe-dev cfe-dev at lists.llvm.org
Wed Feb 26 09:16:33 PST 2020


On 26/02/2020 16:28, Zhihao Yuan wrote:
>> I would be interested to know who is making that statement on behalf of
>> the FreeBSD project. We made a conscious decision not to use symbol
>> versioning for the FreeBSD build of libc++ when we imported it.
> The thread is here; you are welcome to check it out:
> 
> https://lists.freebsd.org/pipermail/freebsd-hackers/2020-February/055669.html

FWIW: Joerg is exactly correct in that thread.  Symbol versioning does 
not solve the problem, for precisely the reasons that he outlines.  C++ 
inline namespaces provide a strictly richer set of functionality than 
ELF symbol versioning and libc++ uses them for ABI stability.  This does 
not help libraries that pass libc++ types across library boundaries.

For example, consider library A defines a function:

void printString(std::string);

Library B calls this function.

Library A is compiled with the current version of libc++.  This function 
is mangled as:

_Z11printStringNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE

Which translates to:

printString(std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char> >)

Now we release a new version of libc++ which provides a new ABI-breaking 
std::string representation and use the __2 inline namespace.  Both can 
coexist in the same libc++ binary.

Library A moves to a new version of libc++ and recompiles against the 
new headers.  Now the same function becomes the mangled equivalent of:

printString(std::__2::basic_string<char, std::__1::char_traits<char>, 
std::__2::allocator<char> >)

(Assuming that char_traits and allocator remain the same).  Now library 
B will get link failures.

Now, it would be possible for library A to explicitly provide a compat 
version of the printString function by providing a function like this:

void printString(std::__2::string);

In C++, if both provide an adequate API, it would even be possible to 
move the implementation into a template that is instantiated in two 
overloads of printString, one with std::__1::string and the other with 
std::string.

Unfortunately, that's the trivial case.  Any classes declared in headers 
exposed by library A will also need compat versions.

Given that most libraries will not go to this trouble, the end result is 
effectively a flag day.  That is not so bad for FreeBSD, where the 
entire package set is built together.  It would be possible to ship a 
version of libc++ that included both the __1 and __2 symbols but 
defaulted to the __2 versions, then rebuild the ports collection (which 
happens at least once a week anyway) against the __2 version once all of 
the older versions of the base system have reached EOL.

David


More information about the cfe-dev mailing list