Skip to content
  • Alex Crichton's avatar
    Add a new wasm32-unknown-wasi target · ace71240
    Alex Crichton authored
    This commit adds a new wasm32-based target distributed through rustup,
    supported in the standard library, and implemented in the compiler. The
    `wasm32-unknown-wasi` target is intended to be a WebAssembly target
    which matches the [WASI proposal recently announced.][LINK]. In summary
    the WASI target is an effort to define a standard set of syscalls for
    WebAssembly modules, allowing WebAssembly modules to not only be
    portable across architectures but also be portable across environments
    implementing this standard set of system calls.
    
    The wasi target in libstd is still somewhat bare bones. This PR does not
    fill out the filesystem, networking, threads, etc. Instead it only
    provides the most basic of integration with the wasi syscalls, enabling
    features like:
    
    * `Instant::now` and `SystemTime::now` work
    * `env::args` is hooked up
    * `env::vars` will look up environment variables
    * `println!` will print to standard out
    * `process::{exit, abort}` should be hooked up appropriately
    
    None of these APIs can work natively on the `wasm32-unknown-unknown`
    target, but with the assumption of the WASI set of syscalls we're able
    to provide implementations of these syscalls that engines can implement.
    Currently the primary engine implementing wasi is [wasmtime], but more
    will surely emerge!
    
    In terms of future development of libstd, I think this is something
    we'll probably want to discuss. The purpose of the WASI target is to
    provide a standardized set of syscalls, but it's *also* to provide a
    standard C sysroot for compiling C/C++ programs. This means it's
    intended that functions like `read` and `write` are implemented for this
    target with a relatively standard definition and implementation. It's
    unclear, therefore, how we want to expose file descriptors and how we'll
    want to implement system primitives. For example should `std::fs::File`
    have a libc-based file descriptor underneath it? The raw wasi file
    descriptor? We'll see! Currently these details are all intentionally
    hidden and things we can change over time.
    
    A `WasiFd` sample struct was added to the standard library as part of
    this commit, but it's not currently used. It shows how all the wasi
    syscalls could be ergonomically bound in Rust, and they offer a possible
    implementation of primitives like `std::fs::File` if we bind wasi file
    descriptors exactly.
    
    Apart from the standard library, there's also the matter of how this
    target is integrated with respect to its C standard library. The
    reference sysroot, for example, provides managment of standard unix file
    descriptors and also standard APIs like `open` (as opposed to the
    relative `openat` inspiration for the wasi ssycalls). Currently the
    standard library relies on the C sysroot symbols for operations such as
    environment management, process exit, and `read`/`write` of stdio fds.
    We want these operations in Rust to be interoperable with C if they're
    used in the same process. Put another way, if Rust and C are linked into
    the same WebAssembly binary they should work together, but that requires
    that the same C standard library is used.
    
    We also, however, want the `wasm32-unknown-wasi` target to be
    usable-by-default with the Rust compiler without requiring a separate
    toolchain to get downloaded and configured. With that in mind, there's
    two modes of operation for the `wasm32-unknown-wasi` target:
    
    1. By default the C standard library is statically provided inside of
       `liblibc.rlib` distributed as part of the sysroot. This means that
       you can `rustc foo.wasm --target wasm32-unknown-unknown` and you're
       good to go, a fully workable wasi binary pops out. This is
       incompatible with linking in C code, however, which may be compiled
       against a different sysroot than the Rust code was previously
       compiled against. In this mode the default of `rust-lld` is used to
       link binaries.
    
    2. For linking with C code, the `-C target-feature=-crt-static` flag
       needs to be passed. This takes inspiration from the musl target for
       this flag, but the idea is that you're no longer using the provided
       static C runtime, but rather one will be provided externally. This
       flag is intended to also get coupled with an external `clang`
       compiler configured with its own sysroot. Therefore you'll typically
       use this flag with `-C linker=/path/to/clang-script-wrapper`. Using
       this mode the Rust code will continue to reference standard C
       symbols, but the definition will be pulled in by the linker configured.
    
    Alright so that's all the current state of this PR. I suspect we'll
    definitely want to discuss this before landing of course! This PR is
    coupled with libc changes as well which I'll be posting shortly.
    
    [LINK]:
    [wasmtime]:
    ace71240