Skip to content

Commit 1dda916

Browse files
committed
Auto merge of #1307 - alexcrichton:wasi-pr, r=gnzlbg
Add intial support for wasm32-unknown-wasi 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]: rust-lang/rust#59464
2 parents 600f635 + bce4454 commit 1dda916

File tree

6 files changed

+938
-5
lines changed

6 files changed

+938
-5
lines changed
+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# In the first container we want to assemble the `wasi-sysroot` by compiling it
2+
# from source. This requires a clang 8.0+ compiler with enough wasm support and
3+
# then we're just running a standard `make` inside of what we clone.
4+
FROM ubuntu:18.04 as wasi-sysroot
5+
6+
RUN apt-get update && \
7+
apt-get install -y --no-install-recommends \
8+
ca-certificates \
9+
clang \
10+
cmake \
11+
curl \
12+
g++ \
13+
git \
14+
libc6-dev \
15+
libclang-dev \
16+
make \
17+
ssh \
18+
xz-utils
19+
20+
# Fetch clang 8.0+ which is used to compile the wasi target and link our
21+
# programs together.
22+
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 -
23+
RUN mv /clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-18.04 /wasmcc
24+
25+
# Note that we're using `git reset --hard` to pin to a specific commit for
26+
# verification for now. The sysroot is currently in somewhat of a state of flux
27+
# and is expected to have breaking changes, so this is an attempt to mitigate
28+
# those breaking changes on `libc`'s own CI
29+
RUN git clone https://github.com/CraneStation/wasi-sysroot && \
30+
cd wasi-sysroot && \
31+
git reset --hard 320054e84f8f2440def3b1c8700cedb8fd697bf8
32+
RUN make -C wasi-sysroot install -j $(nproc) WASM_CC=/wasmcc/bin/clang INSTALL_DIR=/wasi-sysroot
33+
34+
# This is a small wrapper script which executes the actual clang binary in
35+
# `/wasmcc` and then is sure to pass the right `--sysroot` argument which we
36+
# just built above.
37+
COPY docker/wasm32-unknown-wasi/clang.sh /wasi-sysroot/bin/clang
38+
39+
# In the second container we're going to build the `wasmtime` binary which is
40+
# used to execute wasi executables. This is a standard Rust project so we're
41+
# just checking out a known revision (which pairs with the sysroot one we
42+
# downlaoded above) and then we're building it with Cargo
43+
FROM ubuntu:18.04 as wasmtime
44+
45+
RUN apt-get update && \
46+
apt-get install -y --no-install-recommends \
47+
ca-certificates \
48+
clang \
49+
cmake \
50+
curl \
51+
g++ \
52+
git \
53+
libclang-dev \
54+
make \
55+
ssh
56+
57+
RUN curl -sSf https://sh.rustup.rs | sh -s -- -y
58+
ENV PATH=/root/.cargo/bin:$PATH
59+
60+
RUN apt-get install -y --no-install-recommends python
61+
RUN git clone https://github.com/CraneStation/wasmtime-wasi wasmtime && \
62+
cd wasmtime && \
63+
git reset --hard 4fe2d6084e5b5cc74e69a26860f12750df51d339
64+
RUN cargo build --release --manifest-path wasmtime/Cargo.toml
65+
66+
# And finally in the last image we're going to assemble everything together.
67+
# We'll install things needed at runtime for now and then copy over the
68+
# sysroot/wasmtime artifacts into their final location.
69+
FROM ubuntu:18.04
70+
71+
RUN apt-get update && \
72+
apt-get install -y --no-install-recommends \
73+
gcc \
74+
libc6-dev \
75+
libxml2
76+
77+
# Copy over clang we downloaded to link executables ...
78+
COPY --from=reference-sysroot /wasmcc /wasmcc/
79+
# ... and the sysroot we built to link executables against ...
80+
COPY --from=reference-sysroot /wasi-sysroot/ /wasi-sysroot/
81+
# ... and finally wasmtime to actually execute binaries
82+
COPY --from=wasmtime /wasmtime/target/release/wasmtime /usr/bin/
83+
84+
# Of note here is our clang wrapper which just executes a normal clang
85+
# executable with the right sysroot, and then we're sure to turn off the
86+
# crt-static feature to ensure that the CRT that we're specifying with `clang`
87+
# is used.
88+
ENV CARGO_TARGET_WASM32_UNKNOWN_WASI_RUNNER=wasmtime \
89+
CARGO_TARGET_WASM32_UNKNOWN_WASI_LINKER=/wasi-sysroot/bin/clang \
90+
CC_wasm32_unknown_wasi=/wasi-sysroot/bin/clang \
91+
PATH=$PATH:/rust/bin \
92+
RUSTFLAGS=-Ctarget-feature=-crt-static
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/usr/bin/env sh
2+
exec /wasmcc/bin/clang --target=wasm32-unknown-wasi --sysroot /wasi-sysroot "$@"

ci/style.rs

+3
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ fn check_style(file: &str, path: &Path, err: &mut Errors) {
144144
let line = if is_pub {&line[4..]} else {line};
145145

146146
let line_state = if line.starts_with("use ") {
147+
if line.contains("c_void") {
148+
continue;
149+
}
147150
if is_pub {
148151
State::Modules
149152
} else {

libc-test/build.rs

+59-4
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ extern crate ctest;
55

66
use std::env;
77

8-
#[cfg(unix)]
98
fn do_cc() {
10-
cc::Build::new().file("src/cmsg.c").compile("cmsg");
9+
let target = env::var("TARGET").unwrap();
10+
if cfg!(unix) && !target.contains("wasi") {
11+
cc::Build::new().file("src/cmsg.c").compile("cmsg");
12+
}
1113
}
12-
#[cfg(not(unix))]
13-
fn do_cc() {}
1414

1515
fn do_ctest() {
1616
let target = env::var("TARGET").unwrap();
@@ -38,6 +38,7 @@ fn do_ctest() {
3838
t if t.contains("solaris") => return test_solaris(t),
3939
t if t.contains("netbsd") => return test_netbsd(t),
4040
t if t.contains("dragonfly") => return test_dragonflybsd(t),
41+
t if t.contains("wasi") => return test_wasi(t),
4142
_ => (),
4243
}
4344

@@ -1866,3 +1867,57 @@ fn test_dragonflybsd(target: &str) {
18661867

18671868
cfg.generate("../src/lib.rs", "main.rs");
18681869
}
1870+
1871+
fn test_wasi(target: &str) {
1872+
assert!(target.contains("wasi"));
1873+
1874+
let mut cfg = ctest::TestGenerator::new();
1875+
cfg.define("_GNU_SOURCE", None);
1876+
1877+
headers! { cfg:
1878+
"errno.h",
1879+
"fcntl.h",
1880+
"limits.h",
1881+
"locale.h",
1882+
"malloc.h",
1883+
"stddef.h",
1884+
"stdint.h",
1885+
"stdio.h",
1886+
"stdlib.h",
1887+
"sys/stat.h",
1888+
"sys/types.h",
1889+
"time.h",
1890+
"unistd.h",
1891+
"wasi/core.h",
1892+
"wasi/libc.h",
1893+
"wchar.h",
1894+
}
1895+
1896+
cfg.type_name(move |ty, is_struct, is_union| match ty {
1897+
"FILE" => ty.to_string(),
1898+
t if is_union => format!("union {}", t),
1899+
t if t.starts_with("__wasi") && t.ends_with("_u") => {
1900+
format!("union {}", t)
1901+
}
1902+
t if t.starts_with("__wasi") && is_struct => format!("struct {}", t),
1903+
t if t.ends_with("_t") => t.to_string(),
1904+
t if is_struct => format!("struct {}", t),
1905+
t => t.to_string(),
1906+
});
1907+
1908+
cfg.field_name(move |_struct, field| {
1909+
match field {
1910+
// deal with fields as rust keywords
1911+
"type_" => "type".to_string(),
1912+
s => s.to_string(),
1913+
}
1914+
});
1915+
1916+
// Looks like LLD doesn't merge duplicate imports, so if the Rust
1917+
// code imports from a module and the C code also imports from a
1918+
// module we end up with two imports of function pointers which
1919+
// import the same thing but have different function pointers
1920+
cfg.skip_fn_ptrcheck(|f| f.starts_with("__wasi"));
1921+
1922+
cfg.generate("../src/lib.rs", "main.rs");
1923+
}

src/lib.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,10 @@ cfg_if! {
112112
} else if #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] {
113113
mod sgx;
114114
pub use sgx::*;
115-
} else {
115+
} else if #[cfg(target_env = "wasi")] {
116+
mod wasi;
117+
pub use wasi::*;
118+
} else {
116119
// non-supported targets: empty...
117120
}
118121
}

0 commit comments

Comments
 (0)