Skip to content

Conversation

@rioam2
Copy link
Contributor

@rioam2 rioam2 commented Jan 10, 2024

This PR adds support for cross-compiling to wasm32-wasi as a CMake target.

While WebAssembly has many ABI proposals (Emscripten and WASI being the most popular), I have evaluated WASI to be the most stable and future-proof, and therefore, have selected it as the preferred flavor of wasm32. The selection criteria came down to the following points:

  • WASI has better support for various runtime environments than alternative ABIs (f.eks, it can be run in Golang, Rust, Javascript and the Command Line).
  • WASI has a stronger ABI stability guarantee.

The drawback of using WASI is that the proposed specification is not as mature as Emscripten. For example, neither exceptions nor setjmp/longjmp have support as of now. Threading is supported, but requires a specific flavor of the wasi-sdk, which I have chosen not to implement in this PR for simplicity.

Implementation

For this feature, I have bootstrapped wasi-sdk as a CMake toolchain. The SDK is retrieved from the official Github release artifacts, and cached in the same cache directory as vcpkg is.

Using this toolchain, I have integrated it with vcpkg and added a CMake preset to build both the example CLI and module as WebAssembly binaries.

These binaries can be run inside any supported WASI runtime, such as wasmer.io.
My preferred way of testing the CLI program is with wasmer's CLI tool:

# Build the WASM binary
cmake --workflow --preset=wasm32-wasi-clang-static

# Run the binary
curl https://get.wasmer.io -sSfL | sh
wasmer run build/wasm32-wasi-clang-static/src/cli/Debug/<module_name>_cli

This can be run on any host platform or architecture.

Acknowledged shortcomings

As of now, I have not been able to compile Catch2 for wasm32-wasi. This can probably be done using a custom portfile for wasm32, but ends up being severely handicapped because of limited filesystem libc support. As such, the current CMake configuration disables tests when targeting wasm32-wasi. If the WASI standard matures to allow filesystem access, this can be revisited and added for CTest support on WebAssembly. Here is an example branch of how this would be done: https://github.com/rioam2/cpp-project-template/tree/feat-wasm32-wasi-catch2

Exceptions are not specified by the WASI specification nor supported when compiling for wasm32-wasi. This means code in your module cannot make use of try..catch blocks, or throw-ing exceptions. If these wish to be used on other targets, one might need to conditionally insert them using preprocessor checks. I have not yet investigated a better way for accomplishing this that does not degrade the experience for non wasm32-wasi targets.

@rioam2 rioam2 force-pushed the feat/wasm32-wasi-config branch from becaf13 to 8d6516f Compare January 23, 2024 15:29
@rioam2
Copy link
Contributor Author

rioam2 commented Jan 23, 2024

@msvetkin I've now added an overlay port to get the fmt package working on wasm32-wasi.
Now only catch2 does not compile tests for WebAssembly, which is expected since the proposal for WASI has not specified any filesystem access implementations. This will need to wait for the specification to mature more.

feat(wasi): add wasm32-wasi ci runner to template

feat(wasi): fix missed rename

feat(wasi): fix missing bracket

feat(wasi): remove unrelated ninja-mc changes

feat(wasi): do not overwrite system compilers

feat(wasi): hoist -stdlib=libc++ flag in clang presets
feat(wasi): remove catch2 overlay port

feat(wasi): add back usage file to fmt port
@rioam2 rioam2 force-pushed the feat/wasm32-wasi-config branch from 8d6516f to 6382531 Compare January 23, 2024 15:37
@rioam2 rioam2 force-pushed the feat/wasm32-wasi-config branch 5 times, most recently from 17808b4 to 902d011 Compare February 1, 2024 13:41
sudo wget -qO /etc/apt/trusted.gpg.d/llvm.asc https://apt.llvm.org/llvm-snapshot.gpg.key
sudo apt-get update
sudo apt-get install -y -t llvm-toolchain-jammy-17 \
clang-17 llvm-17 lld-17 lldb-17 libc++-17-dev \
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it clang-17 minimum supported version?

add_subdirectory(tests)
if (NOT WASI)
enable_testing()
add_subdirectory(tests)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the issue with tests?

if (WASI)
file(APPEND ${export_file} "\
\n#ifndef WASI_EXPORT\
\n#define WASI_EXPORT(name) extern \"C\" __attribute__((export_name(name)))\
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the issue with generated export macros?

@rioam2 rioam2 force-pushed the feat/wasm32-wasi-config branch from 902d011 to 21e4e10 Compare March 21, 2024 12:25
@rioam2 rioam2 force-pushed the feat/wasm32-wasi-config branch from 01260f9 to c9e34c2 Compare March 21, 2024 12:44
@rioam2 rioam2 force-pushed the feat/wasm32-wasi-config branch from 654a893 to cc2c32a Compare March 21, 2024 13:03
@rioam2
Copy link
Contributor Author

rioam2 commented Jul 22, 2024

Superseded by #13

@rioam2 rioam2 closed this Jul 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants