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

Umm, I am kind of in the similar situation but for windows, basically trying to fully compile the this project Detours
But they kinda abuse C++'s exception to return “Failed” error. eg.

I previously didn’t need to consider these, as my previous use cases never failed, but now it has become an issue.

Any suggestion would be helpful.

It’s hard to say anything without checking the build log.
I found a build.zig in detours. (yours project?)
.linkLibCpp();[1] in Windows will only work with mingw (why? static-[libcxx + llvm-libunwind] building is unsupported in msvc target).

Suggestion:

if (lib.rootModuleTarget().abi != .msvc) {
    lib.linkLibCpp(); // use libcxx + libunwind
} else {
    lib.linkLibC(); // search winsdk+msvc
}

  1. detourz/build.zig at b4cebc88e7cc3562b164b0e45f06b3d4f5edf12c · jhark/detourz · GitHub ↩︎

Yes, I am doing this, Detours/build.zig at b4458f850be15c55a66978e73032e1a6e868183e · IamSanjid/Detours · GitHub

but when I build the tests and run them they exit with 0xc0000005 code at

meaning the __except block is never reached

The tests are 1-to-1 identical to the official repo’s tests, just some changes to make them compileable with windows-gnu version.

Both x86-64_windows_gnu and x86_64_windows_msvc target are exitting with 0xc0000005 code.