I am able to use the wasi-sdk to write C++ apps that run in a canister, and send data in & out over Candid.
I learned that I have to compile the wasi-sdk, llvm-project & wasi-libc with some special flags, -DLIBCXXABI_BAREMETAL=ON and -DLIBCXXABI_ENABLE_ASSERTIONS=OFF
, to avoid getting unsupported imports in the WebAssembly, like these ones:
(module
(type (;0;) (func (param i32 i32) (result i32)))
...
(type (;42;) (func (param i32 i64 i64 i64 i64)))
(import "ic0" "debug_print" (func (;0;) (type 10)))
(import "wasi_snapshot_preview1" "fd_close" (func (;1;) (type 1)))
(import "wasi_snapshot_preview1" "fd_seek" (func (;2;) (type 11)))
(import "wasi_snapshot_preview1" "fd_write" (func (;3;) (type 7)))
However, I have to be very careful not to use certain capabilities of the std library that trigger those types of imports.
I described one of these cases to the wasi-sdk team in this issue, and they provided some tips on how to track down the cause. I am still working on that…
They also asked this question though that I like to ask here:
“Out of interest is there some fundamental reason why you don’t use those
wasi_snapshot_preview1
imports? It is just code size or are you trying to target an environment that doesn’t support WASI? If its the latter, it seems rather odd to be using WASI SDK at all. Obviously we always want to generate the smallest possible binaries but targeting non-WASI host environments is probably out of scope of wasi-sdk.”
I did not answer it yet, because I am not sure what the answer is. I am using the wasi-sdk
because I explored all these options:
- Use clang+±12, targeting wasm
- Use emscripten, targeting standalone wasm
- Use wasi-sdk, out-of-the-box
- Use wasi-sdk, build from source, with flags to avoid external imports that IC does not support
and only option 4 allowed me to use the C++ standard library.
So, after a long story, my question is:
Are the IC canisters actually a non-WASI host environment and I am just going down a wrong path, or does my approach make sense, and I just have to push on and overcome some of these initial hurdles and figure out the best practices of writing C++ code for IC?