Skip to content

Commit

Permalink
Add intiial support for wasm32-unknown-wasi
Browse files Browse the repository at this point in the history
This target is [being proposed][LINK] int he rust-lang/rust repository
and this is intended to get coupled with that proposal. The definitions
here all match the upstream reference-sysroot definitions and the
functions all match the reference sysroot as well. The linkage here is
described more in detail on the Rust PR itself, but in general it's
similar to musl.

Automatic verification has been implemented in the same manner as other
targets, and it's been used locally to develop this PR and catch errors
in the bindings already written (also to help match the evolving sysroot
of wasi). The verification isn't hooked up to CI yet though because
there is no wasi target distributed via rustup just yet, but once that's
done I'll file a follow-up PR to execute verification on CI.

[LINK]:
  • Loading branch information
alexcrichton committed Mar 27, 2019
1 parent 600f635 commit 87def1f
Show file tree
Hide file tree
Showing 5 changed files with 936 additions and 5 deletions.
69 changes: 69 additions & 0 deletions ci/docker/wasm32-unknown-wasi/Dockerfile
@@ -0,0 +1,69 @@
FROM ubuntu:18.04 as reference-sysroot

RUN apt-get update && \
apt-get install -y --no-install-recommends \
ca-certificates \
clang \
cmake \
curl \
g++ \
git \
libc6-dev \
libclang-dev \
make \
ssh \
xz-utils

RUN curl http://releases.llvm.org/8.0.0/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz | tar xJf -
RUN mv /clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-18.04 /wasmcc

RUN git clone https://github.com/CraneStation/reference-sysroot-wasi && \
cd reference-sysroot-wasi && \
git reset --hard d5a609fe63926533e1054e539ba5f2693d51bdf5
RUN make -C reference-sysroot-wasi install -j $(nproc) WASM_CC=/wasmcc/bin/clang INSTALL_DIR=/wasm-sysroot
COPY docker/wasm32-unknown-wasi/clang.sh /wasm-sysroot/bin/clang

FROM ubuntu:18.04 as wasmtime

RUN apt-get update && \
apt-get install -y --no-install-recommends \
ca-certificates \
clang \
cmake \
curl \
g++ \
git \
libclang-dev \
make \
ssh

RUN curl -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH=/root/.cargo/bin:$PATH

RUN apt-get install -y --no-install-recommends python
RUN git clone https://github.com/CraneStation/wasmtime-wasi wasmtime && \
cd wasmtime && \
git reset --hard a7ac05df74759a7536b2b1e30adc6ff4867e36c3

# Install wasmtime in /usr/bin, but make sure to remove rust afterwards because
# we don't want it conflicting with the main Rust we're using to compile
# `libc`.
RUN cargo build --release --manifest-path wasmtime/Cargo.toml

FROM ubuntu:18.04

RUN apt-get update && \
apt-get install -y --no-install-recommends \
gcc \
libc6-dev \
libxml2

COPY --from=reference-sysroot /wasmcc /wasmcc/
COPY --from=reference-sysroot /wasm-sysroot/ /wasm-sysroot/
COPY --from=wasmtime /wasmtime/target/release/wasmtime /usr/bin/

ENV CARGO_TARGET_WASM32_UNKNOWN_WASI_RUNNER=wasmtime \
CARGO_TARGET_WASM32_UNKNOWN_WASI_LINKER=/wasm-sysroot/bin/clang \
CC_wasm32_unknown_wasi=/wasm-sysroot/bin/clang \
PATH=$PATH:/rust/bin \
RUSTFLAGS=-Ctarget-feature=-crt-static
2 changes: 2 additions & 0 deletions ci/docker/wasm32-unknown-wasi/clang.sh
@@ -0,0 +1,2 @@
#!/bin/sh
exec /wasmcc/bin/clang --target=wasm32-unknown-wasi --sysroot /wasm-sysroot "$@"
73 changes: 69 additions & 4 deletions libc-test/build.rs
Expand Up @@ -5,12 +5,12 @@ extern crate ctest;

use std::env;

#[cfg(unix)]
fn do_cc() {
cc::Build::new().file("src/cmsg.c").compile("cmsg");
let target = env::var("TARGET").unwrap();
if cfg!(unix) && !target.contains("wasi") {
cc::Build::new().file("src/cmsg.c").compile("cmsg");
}
}
#[cfg(not(unix))]
fn do_cc() {}

fn do_ctest() {
let target = env::var("TARGET").unwrap();
Expand Down Expand Up @@ -38,6 +38,7 @@ fn do_ctest() {
t if t.contains("solaris") => return test_solaris(t),
t if t.contains("netbsd") => return test_netbsd(t),
t if t.contains("dragonfly") => return test_dragonflybsd(t),
t if t.contains("wasi") => return test_wasi(t),
_ => (),
}

Expand Down Expand Up @@ -1866,3 +1867,67 @@ fn test_dragonflybsd(target: &str) {

cfg.generate("../src/lib.rs", "main.rs");
}

fn test_wasi(target: &str) {
assert!(target.contains("wasi"));

let mut cfg = ctest::TestGenerator::new();
cfg.define("_GNU_SOURCE", None);

headers! { cfg:
"errno.h",
"fcntl.h",
"limits.h",
"locale.h",
"malloc.h",
"stddef.h",
"stdint.h",
"stdio.h",
"stdlib.h",
"sys/stat.h",
"sys/types.h",
"time.h",
"unistd.h",
"wasi/core.h",
"wasi/libc.h",
"wchar.h",
}

cfg.type_name(move |ty, is_struct, is_union| match ty {
"FILE" => ty.to_string(),
t if is_union => format!("union {}", t),
t if t.starts_with("__wasi") && t.ends_with("_u") => format!("union {}", t),
t if t.starts_with("__wasi") && is_struct => format!("struct {}", t),
t if t.ends_with("_t") => t.to_string(),
t if is_struct => format!("struct {}", t),
t => t.to_string(),
});

// This is an opaque struct but we go through shenanigans to define values
// for it
cfg.skip_struct(move |ty| ty == "__clockid");

cfg.field_name(move |_struct, field| {
match field {
// deal with fields as rust keywords
"type_" => "type".to_string(),
s => s.to_string(),
}
});

cfg.skip_static(move |name| {
match name {
// wasi shenanigans for defining CLOCK_REALTIME and such
s if s.starts_with("__CLOCK") => true,
_ => false,
}
});

// Looks like LLD doesn't merge duplicate imports, so if the Rust
// code imports from a module and the C code also imports from a
// module we end up with two imports of function pointers which
// improt the same thing bug have different function pointers
cfg.skip_fn_ptrcheck(|f| f.starts_with("__wasi"));

cfg.generate("../src/lib.rs", "main.rs");
}
5 changes: 4 additions & 1 deletion src/lib.rs
Expand Up @@ -112,7 +112,10 @@ cfg_if! {
} else if #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] {
mod sgx;
pub use sgx::*;
} else {
} else if #[cfg(target_env = "wasi")] {
mod wasi;
pub use wasi::*;
} else {
// non-supported targets: empty...
}
}

0 comments on commit 87def1f

Please sign in to comment.