Skip to content

Conversation

@alexcrichton
Copy link
Collaborator

Almost all functions are stubbed out to return errors. This is all done
in preparation for eventually filling out these functions, but the goal
of this commit is to lay down the scaffolding of the target rather than
actually implement anything.

CI jobs are added to build and test this target. Most tests are expected
to fail, but all tests are still run as usual. Once tests are passing
they'll be updated in CMakeLists.txt to flag the test as expected to
pass instead of expected to fail.

This is a very large PR line-wise, but all the major changes with large
chunks of code are generated code and are expected to be easy to review.
The actual changes here in the source are primarily:

  • Adding #elif defined(__wasip3__) cases
  • Sometimes using the WASIp2 definitions of functions for WASIp3
  • Shuffling naming in the network utilities to support both WASIp2 and
    WASIp3 which have the same types, just renamed.
  • Generated bindings for WASIp3 are now vendored like WASIp2 bindings.
  • Wasmtime is updated for testing to be able to run generated WASIp3
    binaries.

@alexcrichton
Copy link
Collaborator Author

Procedurally, I wanted to open this to showcase my thoughts on what wasm32-wasip3 will look like. This isn't ready for usage (everything, including printing, returns an error and is unimplemented) nor distribution. What it is ready for, however, would be to incrementally land implementations of functions after this PR.

This is split up into a number of commits that I plan to land as separate PRs. For example:

@cpetig
Copy link

cpetig commented Dec 28, 2025

I have a first working stdout implementation for p3 based on this patch at https://github.com/cpetig/wasi-libc/tree/wasip3 .

I guess that p3 needs some more infrastructure (exports_wasi_cli_run_result_void_void_t, exports_wasi_cli_run_run_return, ...) to define wasi:cli/run.run (added in my patch) but this should become a separate object file from wasip3.o to enable reactor type binaries. (In Rust I would use --with to separate the non cli-run parts in wit-bindgen, I think C doesn't have this functionality, yet)

@cpetig
Copy link

cpetig commented Dec 28, 2025

PS:
I can separate the stdout implementation (non-controversial) from run whenever you feel this would be helpful.

@cpetig
Copy link

cpetig commented Dec 28, 2025

See also alexcrichton#1

@alexcrichton
Copy link
Collaborator Author

Thanks! My plan was to land implementation work of actual interfaces as separate PRs to make them easier to review so I'm going to hold off on merging that into this PR's branch, but @cpetig would you be willing to do a follow-up once this PR lands? I'd be happy to review!

@alexcrichton alexcrichton mentioned this pull request Jan 5, 2026
@alexcrichton alexcrichton force-pushed the wasip3 branch 3 times, most recently from 211b32a to 6cb5a05 Compare January 6, 2026 05:51
@cpetig
Copy link

cpetig commented Jan 6, 2026

Thanks! My plan was to land implementation work of actual interfaces as separate PRs to make them easier to review so I'm going to hold off on merging that into this PR's branch, but @cpetig would you be willing to do a follow-up once this PR lands? I'd be happy to review!

😉 My plan with alexcrichton#1 was to show that there is benefit in getting this PR merged even in its incomplete state.

I will rebase the patches and move discussion to https://github.com/WebAssembly/wasi-libc/pulls once this PR is merged.

Almost all functions are stubbed out to return errors. This is all done
in preparation for eventually filling out these functions, but the goal
of this commit is to lay down the scaffolding of the target rather than
actually implement anything.

CI jobs are added to build and test this target. Most tests are expected
to fail, but all tests are still run as usual. Once tests are passing
they'll be updated in `CMakeLists.txt` to flag the test as expected to
pass instead of expected to fail.

This is a very large PR line-wise, but all the major changes with large
chunks of code are generated code and are expected to be easy to review.
The actual changes here in the source are primarily:

* Adding `#elif defined(__wasip3__)` cases
* Sometimes using the WASIp2 definitions of functions for WASIp3
* Shuffling naming in the network utilities to support both WASIp2 and
  WASIp3 which have the same types, just renamed.
* Generated bindings for WASIp3 are now vendored like WASIp2 bindings.
* Wasmtime is updated for testing to be able to run generated WASIp3
  binaries.
@alexcrichton alexcrichton marked this pull request as ready for review January 6, 2026 19:26
@alexcrichton
Copy link
Collaborator Author

Ok all the requisite pieces have now landed so this should be good to go

#include <unistd.h>
#include <utime.h>
#include <values.h>
#include <wasi/__generated_wasip2.h>

Choose a reason for hiding this comment

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

Why __generated_wasip2.h but not __generate_wasip3.h?

Copy link

Choose a reason for hiding this comment

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

because there is a wasm32-wasip3/include-all.c which contains __generate_wasip3.h, I guess.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oh this is due to how include-all.c works. The file is generated here during the check-symbols step and is a #include of all headers located in the sysroot. The sysroot differs from wasip2 to wasip3 due to this cmake logic

The general idea was that I didn't want to tamper with the auto-generated output of wit-bindgen too too much (doing the seds below is already cumbersome enough). I also didn't want header files to be available in a wasip2 sysroot, for example to give access to wasip3 APIs. For example #include <wasi/wasip3.h> expands to nothing on wasm32-wasip2, intentionally so.

@TartanLlama
Copy link

TartanLlama commented Jan 8, 2026

I don't see a p3 version of exports_wasi_cli_run_run, is that intentional? Trying to run through wasmtime at the moment falls back to wasi:cli/[email protected]#run for me. Does that come from wasm-tools?

@cpetig
Copy link

cpetig commented Jan 8, 2026

I don't see a p3 version of exports_wasi_cli_run_run, is that intentional? Trying to run through wasmtime at the moment falls back to wasi:cli/[email protected]#run for me. Does that come from wasm-tools?

There is a rework of wasi:cli/run support in progress at #710 and independently my older implementation in alexcrichton#1 adds it in https://github.com/alexcrichton/wasi-libc/pull/1/files#diff-45b136af96af6bbdf678da48be957d098c7f1cd55981e05e3fa92635b70501a5R113 . I am waiting for these two independent patches to land to rework my patch.

PS: I have some trouble compiling libc++ with your wasip3 llvm version ([l]ldiv[_t] missing in cstdlib), I am not sure whether I fumbled some pre-existing local temporary files or mixed the wrong flavor of sdk+llvm+libc . Still working to gather more details on which combination works (not).

@TartanLlama
Copy link

There is a rework of wasi:cli/run support in progress at #710 and independently my older implementation in alexcrichton#1 adds it in https://github.com/alexcrichton/wasi-libc/pull/1/files#diff-45b136af96af6bbdf678da48be957d098c7f1cd55981e05e3fa92635b70501a5R113 . I am waiting for these two independent patches to land to rework my patch.

Ah, cool, that will likely simplify things for P3 as well as I can make wasm-tools inject code to setup the stack pointer and TLS base rather than having to have an asm entry point for libc.

PS: I have some trouble compiling libc++ with your wasip3 llvm version ([l]ldiv[_t] missing in cstdlib), I am not sure whether I fumbled some pre-existing local temporary files or mixed the wrong flavor of sdk+llvm+libc . Still working to gather more details on which combination works (not).

I haven't tried compiling libc++ with it yet. Sounds like maybe missing compiler-rt?

#include <unistd.h>
#include <utime.h>
#include <values.h>
#include <wasi/__generated_wasip2.h>
Copy link

Choose a reason for hiding this comment

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

because there is a wasm32-wasip3/include-all.c which contains __generate_wasip3.h, I guess.

#include <wasi/version.h>
#include <wasi/wasip1.h>
#include <wasi/wasip2.h>
#include <wasi/wasip3.h>
Copy link

Choose a reason for hiding this comment

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

My question would be more: Why include wasip1.h and wasip3.h in wasm32-wasip2/include-all.c?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point! I sort of arbitrarily decided that I ideally want header files to be present on all targets, but the contents will differ per-target. I don't have the strongest of reasons for doing so, but this means that all these headers are present on all targets, but #ifdef and such means that on any one target only one of these headers actually expands to anything.

@alexcrichton
Copy link
Collaborator Author

For exports_wasi_cli_run_run @cpetig is correct yeah. I didn't really try too too hard to get tests working or anything like that on wasm32-wasip3, it's mostly just building. I think we'll definitely need to copy over some logic from #710 for wasip3 (shouldn't be too too hard)

@cpetig FWIW the change you have of using wasi:cli/command instead of wasi:cli/imports was undone in #641, so we can't in general use wasi:cli/command for the generated bindings libc uses.

PS: I have some trouble compiling libc++ with your wasip3 llvm version ([l]ldiv[_t] missing in cstdlib)

oh dear! If you've got an error message and/or test case I can try to dig in too

Ah, cool, that will likely simplify things for P3 as well as I can make wasm-tools inject code to setup the stack pointer and TLS base rather than having to have an asm entry point for libc.

Agreed!

@cpetig
Copy link

cpetig commented Jan 9, 2026

oh dear! If you've got an error message and/or test case I can try to dig in too

This was caused by an outdated system wide WASI.cmake which set sysroot (last resort solution I went for some weeks ago). Then I tried combining Sy's llvm patch with your patch to enable cmake on libc and my and all our available wasip3 patches on libc.

This went sort of well (I had to define_compiler_rt(wasm32-wasip3) and patch wasi-sdk-sysroot.cmake to use it (add_custom_target) - because of the binary incompatibility all binaries (udiv etc.) compiled for wasip1 will cause a linker failure, so you easily spot mistakes. Then I hit a missing __exception_unwind (loosely remembered symbol) and turned on exceptions for the build.

Now I am down to

.../wasi-sdk/build/sysroot/libcxx-wasm32-wasip3-lto-build-prefix/src/libcxx-wasm32-wasip3-lto-build-build/include/c++/v1/__functional/hash.h:40:8: error: reference to unresolved using declaration
   40 |   std::memcpy(std::addressof(__r), __p, sizeof(__r));
      |        ^
.../wasi-sdk/build/sysroot/libcxx-wasm32-wasip3-lto-build-prefix/src/libcxx-wasm32-wasip3-lto-build-build/include/c++/v1/cstring:82:1: note: using declaration annotated with 'using_if_exists' here
   82 | using ::memcpy _LIBCPP_USING_IF_EXISTS;

which shows me how complicated the situation with (builtin_) memcpy is. But it looks that it might take effort but can moderately easy solved. ⌛

@alexcrichton
Copy link
Collaborator Author

@cpetig ah ok makes sense, given that I think I'll go ahead and merge this so we can start incrementally merging things and moving towards making that more reproducible, for example, in a PR with some changes to help narrow it down.

@alexcrichton alexcrichton merged commit 6036a9f into WebAssembly:main Jan 9, 2026
27 checks passed
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.

3 participants