<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
</head>
<body text="#000000" bgcolor="#FFFFFF">
Hi,<br>
<br>
I'm currently setting up a fresh Linux box (recent Mint, using GCC
4.8 as system compiler) as a dev environment, and since my stuff is
using cutting-edge C++, I want Clang and libc++ for this.
Unfortunately, getting this to work isn't fun at all.<br>
<br>
Clang itself is easy.<br>
<br>
libc++ is anything but. Reading the instructions provided[1], it
looks very much like building with libsupc++, pulled out of the
libstdc++.so, is the best way of doing things. Using libcxxrt (or
libc++abi, but why would I do that on Linux) is listed as having a
little drawback: "Unfortunately you can't simply run clang with
"-stdlib=libc++" at this point, as clang is set up to link for
libc++ linked to libsupc++."<br>
<br>
Therefore I go with this CMake command line:<br>
<br>
<code>CC=clang CXX=clang++ cmake -G Ninja -DLIBCXX_CXX_ABI=libstdc++
-DLIBCXX_LIBSUPCXX_INCLUDE_PATHS="/usr/include/c++/4.8/;/usr/include/</code><code><code>x86_64-linux-gnu/</code>c++/4.8/"
-DCMAKE_BUILD_TYPE=Release <libc++-source-dir></code><br>
<br>
Note that I removed the install prefix so it defaults to /usr/local.
This means I need an ldconfig update after installing, but that part
works. Also, my Clang sits in /usr/local, so the header search path
setup in Clang does the right thing. I'm also using Ninja, but I
tested and it doesn't change anything compared to Makefiles.<br>
<br>
After building and installing, I try to compile a small example
program that uses dynamic_cast and iostreams.<br>
<br>
<font face="monospace">#include <iostream><br>
struct Base { virtual ~Base() {} };<br>
struct Derived : Base {<br>
void x() { std::cout << "Hello, World!\n"; } <br>
};<br>
void foo(Base& b) {<br>
dynamic_cast<Derived&>(b).x();<br>
}<br>
int main() {<br>
Derived d;<br>
foo(d);<br>
}</font><br>
<br>
And I compile it using<br>
<br>
<font face="monospace">$ clang++ -stdlib=libc++ -o hello-llvm
hello.cpp</font><br>
<br>
This fails:<br>
<br>
<font face="monospace">/usr/bin/ld: /tmp/hello-7f7d71.o: undefined
reference to symbol '__cxa_free_exception@@CXXABI_1.3'<br>
/usr/lib/x86_64-linux-gnu/libstdc++.so.6: error adding symbols:
DSO missing from command line<br>
clang-3.5: error: linker command failed with exit code 1 (use -v
to see invocation)</font><br>
<br>
Here's the problem: when building libc++, the linker finds the
various ABI functions in libstdc++, and is quite happy with them
being there. When Clang calls the linker for the actual program,
though, it doesn't pass along a link flag for libstdc++, only for
libc++. Thus, the links fails.<br>
<br>
Ironically enough, I can't even manually add -lstdc++ to the command
line: Clang recognizes this as an attempt to link the standard
library and replaces with with -lc++ - so the final link command has
two -lc++ flags and the link fails with the same error. I have to
give the full path to the library as an input file to make it work.
This is not a good situation.<br>
<br>
If we strike the goal of having only one copy of the C++ ABI stuff
in the final program, even if it links to a C++ library using
libstdc++, then we have more options. Using libcxxrt is on the
table, and so is linking against the static libsupc++ library. The
latter shouldn't use any additional command line flags, so let's try
this:<br>
<br>
<code>CC=clang CXX=clang++ cmake -G Ninja -DLIBCXX_CXX_ABI=libsupc++
-DLIBCXX_LIBSUPCXX_INCLUDE_PATHS="/usr/include/c++/4.8/;/usr/include/</code><code><code>x86_64-linux-gnu/</code>c++/4.8/"
-DCMAKE_BUILD_TYPE=Release <libc++-source-dir></code><br>
<br>
This doesn't work either for some reason:<br>
<br>
<font face="monospace">$ clang++ -stdlib=libc++ -o hello-llvm
hello.cpp<br>
/tmp/hello-3689e5.o: In function `foo(Base&)':<br>
hello.cpp:(.text+0x39): undefined reference to `__dynamic_cast'<br>
hello.cpp:(.text+0x4e): undefined reference to `__cxa_bad_cast'<br>
clang-3.5: error: linker command failed with exit code 1 (use -v
to see invocation)</font><br>
<br>
Using nm to inspect libc++.so, it appears that the linker just
doesn't pull in (or at least export) these two functions. This, in
turn, is probably because it doesn't use them (libc++ doesn't use
dynamic_cast in any compiled code; there's one use in the inline
rethrow_exception, one in the template dynamic_pointer_cast, and one
in an unevaluated context in type_traits). Neither is there any
linker input instructing the linker to pull in the symbol, or an
appropriate use of --whole-archive.<br>
<br>
This again can be worked around by explicitly specifying linking
against the source library, and here -lsupc++ works.<br>
<br>
<br>
The bottom line is that none of the libc++ options on Linux work out
of the box without additional command line arguments beyond
-stdlib=libc++, and the best option (libstdc++, which prevents
duplication of the ABI stuff in a process) is actually the worst
case, because -lstdc++ doesn't work as a workaround.<br>
<br>
<br>
This makes me unhappy. So I did some research into possible
solutions.<br>
<br>
The libsupc++ problem is independent of the others. It basically
comes down to using --whole-archive to pull in libsupc++.a
completely into the resulting .so, not just the parts that happen to
be used. A patch hacking the CMakeLists.txt to do exactly that is
attached.<br>
<br>
<br>
The other problem is this: how do we make it so that no additional
command line flags are required, no matter what ABI library is used?
Ideally, the libc++.so would just tell the linker to pull the ABI
library into the link, or claim to export the symbols itself but
really just forward to the underlying library.<br>
<br>
The first solution is exactly what libtool does, but using the
wrapper isn't really an option, not to mention that it would require
writing the libtool specs manually or using libtool to build libc++.
Neither of these are attractive options. The linker itself does not
have any way of doing this, even though reading the documentation
for --rpath-link makes it sound like it does.<br>
<br>
The second solution is what is done on MacOS. The MachO linker
supports the reexport_library option. Similarly, PE/COFF DLLs on
Windows support such forwarding symbols (kernel32.dll contains lots
of forwarders to ntdll.dll); an OldNewThing article[2] describes
this and the comments contain links to more detailed information.<br>
<br>
It appears, however, from my reading of the ld man page and
extensive web searching, that there is no way to do the equivalent
thing on Linux without actually adding stub forwarders to the
library in question. I have asked on StackOverflow[3], but I don't
really expect an answer.<br>
<br>
So it seems there are these options:<br>
<br>
1) Add stub forwarders to libc++. This is annoying, but it works
with libc++ modifications alone.<br>
2) Have Clang find out by some means what flags, beyond -lc++, are
needed to link against libc++. This information would have to be
provided by libc++ somehow.<br>
3) Have the user tell Clang. For example, -stdlib=libc++ could
instead be -stdlib=libc++-gnuabi or -stdlib=libc++-cxxrt, depending
on the ABI lib. Or the ABI could be a separate option, i.e.
-stdlib=libc++ -abilib=cxxrt. Of course, this is little better than
the state we have now.<br>
<br>
Any thoughts on this? Preferred variant? Things I've overlooked?<br>
<br>
<br>
[1] <a class="moz-txt-link-freetext" href="http://libcxx.llvm.org/">http://libcxx.llvm.org/</a><br>
[2]
<a class="moz-txt-link-freetext" href="http://blogs.msdn.com/b/oldnewthing/archive/2006/07/19/671238.aspx">http://blogs.msdn.com/b/oldnewthing/archive/2006/07/19/671238.aspx</a><br>
[3]
<a class="moz-txt-link-freetext" href="http://stackoverflow.com/questions/22764734/linux-equivalent-of-windows-dll-forwarders-or-macos-reexport-library">http://stackoverflow.com/questions/22764734/linux-equivalent-of-windows-dll-forwarders-or-macos-reexport-library</a><br>
</body>
</html>