I’m working on a project which will target the browser via Wasm, and, unfortunately, a key part of this project is a library written in C++. Given Zig’s great support for compiling Zig and even C to Wasm (using WASI via wasi-libc), and given this library doesn’t do anything like graphics or audio where Emscripten would be needed, I figured it might “just work”, but unfortunately C++ exceptions are giving me some issues.
I’ll document what I’ve tried so far below, but just to preface this with a question: has anyone successfully used Zig to compile C++ (using the C++ standard library) to Wasm/WASI without resorting to Emscripten?
Here’s my very simple example program:
#include <iostream>
int main() {
std::cout << "Hello, world!" << std::endl;
return 0;
}
If I try to compile this using zig build-exe -target wasm32-wasi -lc++ main.cpp
, I get the following error:
error: wasm-ld: /home/ian/.cache/zig/o/d0437116c48db9b675834f561e3055cf/libc++abi.a(/home/ian/.cache/zig/o/b79e1fcbfe3ba7adfe32cdcfe055da93/cxa_exception.o): undefined symbol: _Unwind_RaiseException
This makes sense: the default Wasm “CPU” used in Zig is the lime1 feature set, which includes no support for exception handling. But libunwind does have Wasm support via the widely supported (in browsers) exception handling proposal, so my first thought was to try that: zig build-exe -target wasm32-wasi -mcpu lime1+exception_handling -lc++ main.cpp
Now I run into a Clang bug (which I will need to figure out how to properly report upstream edit: reported upstream: Clang crash when compiling libc++ for Wasm with `-mexception-handling` · Issue #148550 · llvm/llvm-project · GitHub):
Compiler output
error: sub-compilation of libcxxabi failed
:1:1: note: clang frontend command failed with exit code 139 (use -v to see invocation)
:1:1: note: diagnostic msg:
********************
PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
:1:1: note: diagnostic msg: /tmp/stdlib_new_delete-898c18.cpp
:1:1: note: diagnostic msg: /tmp/stdlib_new_delete-898c18.sh
:1:1: note: diagnostic msg:
********************
:1:1: note: clang frontend command failed with exit code 139 (use -v to see invocation)
:1:1: note: diagnostic msg:
********************
PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
:1:1: note: diagnostic msg: /tmp/cxa_personality-9c5fcf.cpp
:1:1: note: diagnostic msg: /tmp/cxa_personality-9c5fcf.sh
:1:1: note: diagnostic msg:
********************
error: sub-compilation of libcxx failed
:1:1: note: clang frontend command failed with exit code 139 (use -v to see invocation)
:1:1: note: diagnostic msg:
********************
PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
:1:1: note: diagnostic msg: /tmp/new-ec2e48.cpp
:1:1: note: diagnostic msg: /tmp/new-ec2e48.sh
:1:1: note: diagnostic msg:
********************
:1:1: note: clang frontend command failed with exit code 139 (use -v to see invocation)
:1:1: note: diagnostic msg:
********************
PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
:1:1: note: diagnostic msg: /tmp/string-881880.cpp
:1:1: note: diagnostic msg: /tmp/string-881880.sh
:1:1: note: diagnostic msg:
********************
:1:1: note: clang frontend command failed with exit code 139 (use -v to see invocation)
:1:1: note: diagnostic msg:
********************
PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
:1:1: note: diagnostic msg: /tmp/ios-85bd41.cpp
:1:1: note: diagnostic msg: /tmp/ios-85bd41.sh
:1:1: note: diagnostic msg:
********************
So compiling with exception handling doesn’t seem to be possible, but the library I’m using doesn’t use exceptions anyway, so I figured I could just disable them entirely using -fno-exceptions
. However, it seems that Zig currently doesn’t support disabling exceptions for libc++ (Add ability for zig c++ to compile libcxx and libcxxab with -fno-exceptions · Issue #17470 · ziglang/zig · GitHub), so even if I use -fno-exceptions
, I still get a linker error related to _Unwind_RaiseException
.
The last resort would be to just rewrite the library in Zig and avoid this entirely, which I may do at some point, but that would be a pretty big yak shave at this point