Why doesn't clang++ have a -static-libc++ option?

There seems to be no direct way to statically link libc++abi.a while still using shared libraries such as libm.so, etc. The following will not work on a linux machine that has no /lib64/libm.a (only /lib64/libm.so is available):

clang++ -static -stdlib=libc++ hello.cpp -lc++abi

The above fails due to unresolved symbols from the math library (our machines don’t have /lib64/libm.a installed).

The following doesn’t work either:

clang++ -stdlib=libc++ hello.cpp -Wl,-Bstatic -lc++abi -Wl,-Bdynamic

It picks up libc++abi.so rather than libc++abi.a.

The only thing that I could get to work was to copy libc++.a, libc++abi.a, etc. into a separate directory, say, <staticpath> (that contains only .a files and no .so files) and then use -Wl,-Bstatic -L <staticpath> -lc++abi -Wl,-Bdynamic. This works (the resultant executable has no dependency on libc++.so and libc++abi.so).

With libstdc++, it is much easier to do this because we have the -static-libstdc++, -static-libgcc, options. Why doesn’t clang++ provide equivalent -static-libc++, etc.?

If I remember correctly -static-libstdc++ works with libc++ as well. You just specify both -static-libstdc++ -stdlib=libc++. I think there was a suggestion to rename the option at some point. Another option would be for us to add a alias for -static-libc++. But try it first and see if it works.

-stdlib=libc++ -static-libstdc++

gives a lot of undefined symbols:

ld.lld: error: undefined symbol: operator new(unsigned long)                                                                                                                                                                                                  
>>> referenced by future.cpp                                                                                                                                                                                                                                  
>>>               future.cpp.o:(std::__1::__future_error_category::message(int) const) in archive /global/install/bin/../lib/x86_64-unknown-linux-gnu/libc++.a                                                                               
>>> referenced by future.cpp                                                                                                                                                                                                                                  
>>>               future.cpp.o:(std::__1::__future_error_category::message(int) const) in archive /global/install/bin/../lib/x86_64-unknown-linux-gnu/libc++.a                                                                               
>>> referenced by future.cpp                                                                                                                                                                                                                                  
>>>               future.cpp.o:(std::__1::__future_error_category::message(int) const) in archive /global/install/bin/../lib/x86_64-unknown-linux-gnu/libc++.a                                                                               
>>> referenced 185 more times                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                              
ld.lld: error: undefined symbol: __cxa_guard_acquire                                                                                                                                                                                                          
>>> referenced by future.cpp                                                                                                                                                                                                                                  
>>>               future.cpp.o:(std::__1::future_category()) in archive /global/install/bin/../lib/x86_64-unknown-linux-gnu/libc++.a                                                                                                         
>>> referenced by future.cpp                                                                                                                                                                                                                                  
>>>               future.cpp.o:(std::__1::__throw_future_error[abi:v170000](std::__1::future_errc)) in archive /global/install/bin/../lib/x86_64-unknown-linux-gnu/libc++.a                                                                  
>>> referenced by future.cpp                                                                                                                                                                                                                                  
>>>               future.cpp.o:(std::__1::promise<void>::~promise()) in archive /global/install/bin/../lib/x86_64-unknown-linux-gnu/libc++.a                                                                                                 
>>> referenced 114 more times
:
:                                                                                                                                                          

I can make the undefined symbols go away by adding -lc++abi as well. However, the resultant executable depends on libc++abi.so and libunwind.so.

The only command line that produces an executable with no shared library dependencies on libc++.so, libc++abi.so and libunwind.so is when -L is specified to a separate directory containing libunwind.a, libc++.a and libc++abi.a (no .so’s in that directory) followed by -lc++abi.

Try -l:libc++abi.a
This should prefer static library over shared.

In order to create static binaries with libc++ I have found that creating a libc++.a with libc++abi embedded is the most straightforward way. That means enabling the options -DLIBCXX_STATICALLY_LINK_ABI_IN_STATIC_LIBRARY -DLIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY which will merge libunwind into libc++abi and libc++abi into libc++.

It takes a few tries to get the cmake options right, but then it’s pretty smooth sailing, because you can use -static-libstdc++ without any additional options.

I know that @tamas maintains a toolchain that does this.

3 Likes