Zig C++ and exception ABI on Linux

Hi there,

My team is shipping a C++ shared library on several platforms. One of our targets is a custom Linux platform with a fairly old toolchain, which prevents us from using modern C++ features. So I thought about replacing this compiler with Zig C++.

I did some tests, and I manage to build with Zig C++, there are however issues related to ABI, since Zig uses libc++ instead of libstdc++.

First of all, we fortunately do not expose the STL, so there is no risk of symbol incompatibilities if someone links to our libraries with an executable using libstdc++.

However, when building an executable with the original toolchain and linking it with our library build with zig (which works), I noticed that if I threw an exception in our library, it couldn’t be caught in the executable and caused the program to abort. This is even though the exception is a custom exception type that does not depend at all on the STL. It seems that the way LLVM and gcc handle exceptions is different, preventing us from throwing exceptions across boundaries.

My question is: is there any way around it? Would it work if we dynamically linked with the target’s libgcc?
Do we have to use libstdc++? If so, do we have to use the target’s version, or can we statically link with a more recent version and the ABI will be compatible?
Or am I daydreaming, and there is no way to achieve this using Zig?

Any help would be appreciated.

Yes, it is possible but very trivial.

Unlike other toolchains that follow the system standard.
Zig on linux replaces:

ABI GNU LLVM
C++ libstdc++ & libsupc++ libc++ & libc++abi
EH libgcc_s libunwind (llvm version)
Compiler libgcc libcompiler-rt (zig-port)

Just like msvc target currently does. Freestanding will work. Passing the (preferably shared) libraries explicitly.

E.g.:

GTKmm 4 build:

$ zig c++ base.cc $(pkg-config gtkmm-4.0 --cflags --libs) -o gtk_test /usr/lib/libstdc++.so /usr/lib/libgcc_s.so -I/usr/include/c++/13.2.1/x86_64-pc-linux-gnu -I/usr/include/c++/13.2.1 -nostdinc++ -nostdlib++ -L/usr/lib/gcc/x86_64-pc-linux-gnu/13.2.1 -lgcc

References

1 Like

There are flags that select the runtime libraries.
For gnu: -unwindlib=libgcc -rtlib=libgcc -stdlib=libc++
For llvm: -unwindlib=libunwind -rtlib=compiler-rt -stdlib=libstdc++
The advantage over nostdlib++ and nostdinc++ is that you don’t need to specify include and library paths and library names.

EDIT: as @kassane demostrated this works with clang++ but does not work with zig c++.

By the way, @Aym welcome to ziggit :slight_smile:

1 Like

Wow, so nice to see people responding so quickly on (what I assumed was) such a niche topic!

OK, so let me get my head around what you guys just wrote. So, I can either use nostdlib++ and nostdinc++, in which case I have to provide the libraries myself. Or I can use the unwindlib, rtlib and stdlib, in which case the zig compiler will use the correct libraries? Will I need the sources for libstdc++ in that case? Or will it work on its own? And will it link the stdlib statically or dynamically?

@dimdin Thanks! I’ve been looking at zig for some time, mainly lurking on the Zig subreddit. It looks great, even to a RAII junkie like me! Looking forward to trying it more.

Yeah! However, for zig there’s no guarantee that all of the existing clang commands are working.

$ zig c++ -unwindlib=libunwind -rtlib=compiler-rt -stdlib=libstdc++ pmr_bench.cc -fuse-ld=ld -o pmr_test
zig: warning: argument unused during compilation: '-unwindlib=libunwind' [-Wunused-command-line-argument]
zig: warning: argument unused during compilation: '-rtlib=compiler-rt' [-Wunused-command-line-argument]
zig: warning: argument unused during compilation: '-stdlib=libstdc++' [-Wunused-command-line-argument]
zig: warning: argument unused during compilation: '-fuse-ld=ld' [-Wunused-command-line-argument]

Reference

1 Like