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 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.
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.
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.