clang -static-libstdc++ equivalent for libc++?
Asked Answered
I

1

6

I'm using clang 10 and gcc 9 on Ubuntu 20.04.

Taking this following sample program:

#include <cstdio>
#include <any>

int main(int argc, char* argv[])
{
    std::any v = argc;
    printf("value: %d\n", std::any_cast<int>(v));
}

I can compile it with clang like this: clang++ test.cpp -std=c++20 -static-libstdc++ -static-libgcc and end up with this binary:

$ ldd a.out
    linux-vdso.so.1 (0x00007fffd92f9000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f169be49000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f169bc57000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f169bf9e000)

Now I'd like to use LLVM's libc++ in my program and link it statically, just as I'm linking libstdc++ statically above. But there's no -static-libc++ equivalent; I can do this:

clang++ test.cpp -std=c++20 -stdlib=libc++ -static-libstdc++ -static-libgcc

but then I receive many link errors due to the fact that libc++abi is not linked. Running the above command with -v further confirms the suspicion:

"/usr/bin/ld" [...] /tmp/test2-f20a4a.o -Bstatic -lc++ -Bdynamic -lm -lgcc -lgcc_eh
#                                            ^^^^^^^^^^^ no -lc++abi!
 -lc -lgcc -lgcc_eh /usr/bin/../lib/gcc/x86_64-linux-gnu/9/crtend.o /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o

There is a -static option available, but that's not the same: it links everything statically, including libc, which is generally recommended against (and, on my system, it still doesn't link libc++abi and produces multiple link errors).

The best way I've been able to find is to link in a separate step, pass -nostdlib++ and manually pass linker flags to statically link libc++ and libc++abi:

clang++ test.cpp -std=c++20 -stdlib=libc++ -c
clang++ test.o -nostdlib++ -static-libgcc -Wl,--push-state -Wl,-Bstatic -lc++ -lc++abi -Wl,--pop-state -lpthread
ldd a.out
        linux-vdso.so.1 (0x00007fff20dfe000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9ef6a97000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9ef6948000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9ef6756000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f9ef6ac0000)

This does work, but it seems strange that clang wouldn't support doing this more readily, without manually messing with the linker. Is there no other way?

Ideatum answered 24/4, 2022 at 18:13 Comment(1)
According to this -static-libstdc++ works for libc++ as well for newer versions of Clang. It worked for me with Clang 14, but not with Clang 10.Philhellene
S
3

This works (tested on clang 16), using -l:libc++abi.a:

$ clang++ test.cpp -std=c++20 -stdlib=libc++ -static-libstdc++ -l:libc++abi.a -static-libgcc 
$ ldd a.out
    linux-vdso.so.1 (0x00007fff1bf60000)
    libm.so.6 => /lib64/libm.so.6 (0x00007f409319d000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f4092fc0000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f40932da000)
$ ./a.out  
value: 1

-stdlib=libc++ -static-libstdc++ -l:libc++abi.a certainly looks weird but it seems to do the right thing.

Semeiology answered 26/7, 2023 at 16:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.