-
Notifications
You must be signed in to change notification settings - Fork 200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: add wasm32-wasi-preview2
target, prioritizing wasi-sockets
support
#447
Comments
Sounds like a good plan, although I'm not sure about the use of the new target triples. In the past we have talked about trying not to let all our build variants result in proliferation of target triples. Presumably the preview2 stuff all lives deep inside of libc itself, so won't effect user-level object files. e.g. one won't need to rebuild everything from source just to link against this new flavor of libc? |
Yeah, @alexcrichton and I were brainstorming ways to incrementally add Preview 2 support (specifically
Correct -- they'll only need to rebuild if they want to use the new Preview 2-only features. |
Wouldn't they even need to rebuild the object files though? I'm assuming the public headers don't need to change between preview1 and preview2, only the implementation within libc itself. So the same object code and link with this new flavor of libc and work just fine.. they would just get a different implementation of e.g. the e.g.: Wouldn't something like this work:
|
I do think it's theoretically possible to support a single sysroot maybe and something like |
You could also have two different sysroots without changing the triple:
I seem to remember from previous discussions that we didn't want to create a lot of new target triples on the llvm / wasi-libc side? It seems like rust like to use target triple all this stuff but I want to avoid taking that route just because of the rust inertia. If it makes sense not to have so many triples out there then perhaps we should instead be pushing back against rust. Maybe this is a case were a new triple makes sense? I'm not totally sure. For threads I think we decided it did. For other features it might not make sense. Are you proposing a new triple for each iteration? i.e. preview3 and preview4 would also get triples? |
I personally agree that in theory one triple or not many triples would be best, but I don't think that it's actually possible to achieve that. Following Rust here to me isn't just inertia, it's well-motivated independently. Each triple requires an entire rebuild of libc, or a separate sysroot, at minimum. This means that to wasi-libc it's a bunch of
Adding a target is a big thing in my opinion and isn't something that should be taken lightly, but the transition to the component model is a big deal and additionally isn't something that can be taken lightly. For example the Rust compiler I'm proposing it use a wrapper around
Yes. This is expected to be on the timescale of years, however, and the old targets will get phased out. There is no timeline at this point for preview3, and it's in the future so we don't even know exactly what it might look like. Part of the possible development of preview3 and breaking changes would take into account that it's a bummer to add targets to all the languages. That may mean this never ends up happening, we basically need to ship preview2 to figure out the answer. |
Thanks for all the clarifying data, my intent here is was only to make sure we were considering this stuff carefully and it sounds like you have. |
those targets won't have any actual ABI differences when you just do |
I propose we don't try to guarantee full ABI compatibility between the two targets. I'm aware that full ABI compatibility would be nice to have, but ABIs are tricky to preserve when doing cross-cutting changes like preview1->preview2, so we were to guarantee that, we'd really want much more comprehensive ABI compatibility testing, to protect users from silent accidental ABI breakage. Also, the preview1 ABI contains types and constants from cloudabi and preview1 which would benefit from being updated for preview2. |
I would also say that in addition to what @sunfishcode already said the preview2 target is already planned to have incompatible ABIs. Less so at the actual "this type is this size" level but an example is a file descriptor. In preview1 a "file descriptor" is handed off to Overall there is so much different about preview2 that, as I mentioned above, historical discussions about this have always pointed in the direction of a new target. There's not disagreement that a second sysroot or a second binary copy of libc could work, but my post above explains why there are issues beyond that isolated technical issue which are better solved with a second target. |
I agree there may be ABI differences but with wasi-libc aren't they mostly hidden by the libc abstraction? libc-using code that uses things like (Also, note that we don't currently prevent linking of object files built with different targets since the target is not currently encoded in the object file. We have talking about adding this feature though). |
If a project exclusively used wasi-libc and nothing else, then yes it could work with either a preview1 or preview2 sysroot without modification. Having worked on the WASI targets in Rust which use wasi-libc, that is not the case there for sure. My experience is that in general it's pretty rare for a non-trivial program to use only libc and literally nothing else. The interop is what I'm chiefly worried about and where it's extremely useful to have a high-level distinction to talk to end developers about what to target and how to shape their own build processes/etc. |
I'm not sure if this is useful feedback, as it applies more to Rust than wasi-libc, but here goes: TinyGo uses wasi-libc to target WASI Preview 1, but mainline Go targets the WASI Preview 1 APIs directly. Given the abstraction level of the Component Model vs the C ABI style of Preview 1, would it make sense for Rust to implement guest bindings for Preview 2 / Component Model directly, rather than via wasi-libc? (Related: work is in progress to target Preview 2 directly in TinyGo instead of depending on wasi-libc and the P1->P2 adapter.) Edit: I also wonder if a native Rust implementation of a Preview 2 guest would be help to inform a C implementation here. |
That's a good question, and is something that's been considered when talking to folks historically, but the conclusion has generally been that it's desirable to be able to link Rust and C (and maybe C++) into the same WebAssembly binary. In that situation it's best to have wasi-libc as a base set of abstractions. Otherwise it would be impossible to communicate sockets between Rust and C, for example, since C would think a socket is a file descriptor when in Rust it'd be a collection of WASI preview2 resources. |
How often does that happen in practice? For the cases in which it does might it be preferable to provide a C wrapper around a memory-safe implementation if interop is required? Would this just apply to wasi:cli or to higher level components like wasi:http as well? |
We are getting off topic here but I can think of a couple more arguments for a given language runtime to use wasi-libc rather than directly binding to wasi syscall layer:
|
while comprehensive testing is great to have, the lack of it is not a good enough reason to give up compatibility, IMO.
for example? |
it sounds like something which most of the user applications never do. |
does this mean to have an equivalent of the |
|
Zig (not The builtin In that context, preserving ABI compatibility would be immensely useful. And it is not too late to do it. That would also make it way easier to pass descriptors between Zig code and code using |
@jedisct1 Please understand that ABI comptibility would be a lot of work. And it's work that neither you nor anyone else appears to be volunteering to help with. |
Here's a list of Rust crates which currently use WASI Preview 1 host functions directly, ordered by popularity: https://crates.io/crates/wasi/reverse_dependencies. Over time, we'll want them to migrate to Preview 2, but that will take a while, and some might choose to do so incrementally. |
Yes, exactly: https://github.com/dicej/wasi-libc/blob/sockets/libc-bottom-half/headers/private/reactor.h and https://github.com/dicej/wasi-libc/blob/sockets/libc-bottom-half/cloudlibc/src/libc/sys/wasi_preview2/reactor.c. |
Yes, although now I'm thinking I might add an
First, check to see if there's an entry in the descriptor->handle table. If so, pass the handle(s) to preview2 call(s). If not, pass the descriptor to preview1 call(s). |
This is to be used by `wasi-libc` to reserve file descriptors for its own use (e.g. for sockets), ensuring that any attempt to pass them directly to Preview 1 functions will consistently return an error. See WebAssembly/wasi-libc#447 for further details. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
* add `adapter_{open|close}_badfd` exports to Preview 1 adapter This is to be used by `wasi-libc` to reserve file descriptors for its own use (e.g. for sockets), ensuring that any attempt to pass them directly to Preview 1 functions will consistently return an error. See WebAssembly/wasi-libc#447 for further details. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * add `preview2_adapter_badfd` test Signed-off-by: Joel Dice <joel.dice@fermyon.com> --------- Signed-off-by: Joel Dice <joel.dice@fermyon.com>
…dealliance#7663) * add `adapter_{open|close}_badfd` exports to Preview 1 adapter This is to be used by `wasi-libc` to reserve file descriptors for its own use (e.g. for sockets), ensuring that any attempt to pass them directly to Preview 1 functions will consistently return an error. See WebAssembly/wasi-libc#447 for further details. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * add `preview2_adapter_badfd` test Signed-off-by: Joel Dice <joel.dice@fermyon.com> --------- Signed-off-by: Joel Dice <joel.dice@fermyon.com>
* add `adapter_{open|close}_badfd` exports to Preview 1 adapter (#7663) * add `adapter_{open|close}_badfd` exports to Preview 1 adapter This is to be used by `wasi-libc` to reserve file descriptors for its own use (e.g. for sockets), ensuring that any attempt to pass them directly to Preview 1 functions will consistently return an error. See WebAssembly/wasi-libc#447 for further details. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * add `preview2_adapter_badfd` test Signed-off-by: Joel Dice <joel.dice@fermyon.com> --------- Signed-off-by: Joel Dice <joel.dice@fermyon.com> * Update `*_badfd` methods in the adapter to return an errno (#7672) Makes them a bit more consistent with the rest of the WASI functions as opposed to returning a boolean. --------- Signed-off-by: Joel Dice <joel.dice@fermyon.com> Co-authored-by: Alex Crichton <alex@alexcrichton.com>
Currently, this is identical to the `wasm32-wasi` in all but name. See WebAssembly#449 for the next step, which is to incrementally add Preview 2 features, e.g. `wasi-sockets`. Per the discussion in that PR, I've split the `wasi-sysroot/include` directory into per-target directories. Eventually, we'll want to build a separate sysroot for each target, but there's currently uncertainty about how to configure the default sysroot for e.g. clang, so we're not tackling that yet. See also WebAssembly#447 for further details. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
Currently, this is identical to the `wasm32-wasi` in all but name. See WebAssembly#449 for the next step, which is to incrementally add Preview 2 features, e.g. `wasi-sockets`. Per the discussion in that PR, I've split the `wasi-sysroot/include` directory into per-target directories. Eventually, we'll want to build a separate sysroot for each target, but there's currently uncertainty about how to configure the default sysroot for e.g. clang, so we're not tackling that yet. See also WebAssembly#447 for further details. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
Currently, this is identical to the `wasm32-wasi` in all but name. See #449 for the next step, which is to incrementally add Preview 2 features, e.g. `wasi-sockets`. Per the discussion in that PR, I've split the `wasi-sysroot/include` directory into per-target directories. Eventually, we'll want to build a separate sysroot for each target, but there's currently uncertainty about how to configure the default sysroot for e.g. clang, so we're not tackling that yet. See also #447 for further details. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
i have been told preview2 does not require component-model. at least, this adapter-based approach doesn't seem compatible with the direct use of preview2 from core wasm module. |
Almost all of the existing tooling to support Preview 2 involves the Component Model to some degree, but it's also true that it can be supported at the core module level as well. In the latter case, a host must still implement a subset of the Component Model, e.g. the canonical ABI for converting between high-level component types and low-level core Wasm types, analogous to the WITX ABI used in Preview 1. Ideally, a host that supports Preview 2 at the module level would also use the component type custom section (if available) to verify that the guest component types match what the host expects (i.e. not just that the core Wasm types match). Regarding the adapter: @cpetig has been releasing static library builds which should allow it to be linked into a module as an alternative to using |
Quick update on this: all the To my knowledge, no work has yet been done to switch from p1 to p2 APIs outside of |
Summary
This is a proposal to add wasi-sockets support to
wasi-libc
as a first step towards full WASI Preview 2 support. This includes adding a newwasm32-wasi-preview2
build target to differentiate it from the existingwasm32-wasi{-threads}
targets based on WASI Preview 1.Background
WASI Preview 2 has been under development for a few years and should be finalized by the end of 2023 or early 2024. Unlike Preview 1, which was defined using WITX and core WebAssembly specification, Preview 2 is based on WIT and the Component Model proposal. In addition, Preview 2 uses unforgeable resource handles instead of file descriptors to track files, sockets, and other host resources.
In order to ease the transition from Preview 1 to Preview 2, the Wasmtime team has created an adapter which may be used with wit-component to convert modules targeting Preview 1 into components targeting Preview 2. Therefore, any toolchain targeting Preview 1 can be used in combination with the adapter and
wit-component
to generate Preview 2 components. Moreover, developers can use tools like wit-bindgen to access Preview 2 features beyond the scope of Preview 1, including full TCP and UDP socket support viawasi-sockets
and high-level HTTP support via wasi-http, with additional interfaces in the works (e.g. wasi-cloud-core).However, using
wasi-sockets
via direct host calls is akin to doing networking on native platforms via syscalls, bypassing libc and/or the standard library of the language being used. That makes reusing third-party, network-aware libraries such as database drivers difficult or impossible since they are normally designed to use the relevant standard library. So while it is technically possible to usewasi-sockets
in applications today, it will not be ergonomic or practical until the standard libraries of various programming languages have been ported to use it, starting withwasi-libc
.On the other hand, standard libraries with existing Preview 1 support for features such as filesystem access, env variables, clocks, etc. will continue to work in a Preview 2 environment via the adapter, so there's less urgency to update those parts of
wasi-libc
to use Preview 2 directly.Proposal
Given the situation described above, we're proposing to create a new
wasm32-wasi-preview2
build target forwasi-libc
andwasi-sdk
which will initially use the Preview 1 host APIs (as implemented by the Preview 1->2 adapter) for everything except sockets, which will bypass the adapter and use the Preview 2 host APIs directly. From there, we'll incrementally replace the Preview 1 parts with their Preview 2 equivalents until the adapter is no longer needed at all.During the transition period,
wasi-libc
and the adapter will share responsibility for mapping Preview 1 file descriptors to Preview 2 resource handles, with the former handling sockets and the latter handling files and stdio. In order to avoid confusion (e.g. bothwasi-libc
and the adapter using the same descriptor to mean different things), we'll add a newadapter_open_badfd
function to the adapter, whichwasi-libc
will use to reserve descriptors for its use, indicating that the adapter should returnEBADF
if it receives any Preview 1 calls for such descriptors besidesfd_close
.Testing
Currently,
wasi-libc
relies on a subset of a fork ofmusl
's libc-test suite for testing. We plan to expand that subset to include all relevant socket tests. In addition, we'll be updating the Rust and Python standard libraries to match progress made inwasi-libc
, enabling the socket tests in their test suites as well.Prototype
I've created experimental forks of the wasi-libc, the adapter, and Rust, along with a test harness that demonstrates the use of
wasi-sockets
via the Rust standard library.The text was updated successfully, but these errors were encountered: