Skip to content

Commit 87def1f

Browse files
committed
Add intiial 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]:
1 parent 600f635 commit 87def1f

File tree

5 files changed

+936
-5
lines changed

5 files changed

+936
-5
lines changed
+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
FROM ubuntu:18.04 as reference-sysroot
2+
3+
RUN apt-get update && \
4+
apt-get install -y --no-install-recommends \
5+
ca-certificates \
6+
clang \
7+
cmake \
8+
curl \
9+
g++ \
10+
git \
11+
libc6-dev \
12+
libclang-dev \
13+
make \
14+
ssh \
15+
xz-utils
16+
17+
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 -
18+
RUN mv /clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-18.04 /wasmcc
19+
20+
RUN git clone https://github.com/CraneStation/reference-sysroot-wasi && \
21+
cd reference-sysroot-wasi && \
22+
git reset --hard d5a609fe63926533e1054e539ba5f2693d51bdf5
23+
RUN make -C reference-sysroot-wasi install -j $(nproc) WASM_CC=/wasmcc/bin/clang INSTALL_DIR=/wasm-sysroot
24+
COPY docker/wasm32-unknown-wasi/clang.sh /wasm-sysroot/bin/clang
25+
26+
FROM ubuntu:18.04 as wasmtime
27+
28+
RUN apt-get update && \
29+
apt-get install -y --no-install-recommends \
30+
ca-certificates \
31+
clang \
32+
cmake \
33+
curl \
34+
g++ \
35+
git \
36+
libclang-dev \
37+
make \
38+
ssh
39+
40+
RUN curl -sSf https://sh.rustup.rs | sh -s -- -y
41+
ENV PATH=/root/.cargo/bin:$PATH
42+
43+
RUN apt-get install -y --no-install-recommends python
44+
RUN git clone https://github.com/CraneStation/wasmtime-wasi wasmtime && \
45+
cd wasmtime && \
46+
git reset --hard a7ac05df74759a7536b2b1e30adc6ff4867e36c3
47+
48+
# Install wasmtime in /usr/bin, but make sure to remove rust afterwards because
49+
# we don't want it conflicting with the main Rust we're using to compile
50+
# `libc`.
51+
RUN cargo build --release --manifest-path wasmtime/Cargo.toml
52+
53+
FROM ubuntu:18.04
54+
55+
RUN apt-get update && \
56+
apt-get install -y --no-install-recommends \
57+
gcc \
58+
libc6-dev \
59+
libxml2
60+
61+
COPY --from=reference-sysroot /wasmcc /wasmcc/
62+
COPY --from=reference-sysroot /wasm-sysroot/ /wasm-sysroot/
63+
COPY --from=wasmtime /wasmtime/target/release/wasmtime /usr/bin/
64+
65+
ENV CARGO_TARGET_WASM32_UNKNOWN_WASI_RUNNER=wasmtime \
66+
CARGO_TARGET_WASM32_UNKNOWN_WASI_LINKER=/wasm-sysroot/bin/clang \
67+
CC_wasm32_unknown_wasi=/wasm-sysroot/bin/clang \
68+
PATH=$PATH:/rust/bin \
69+
RUSTFLAGS=-Ctarget-feature=-crt-static
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/sh
2+
exec /wasmcc/bin/clang --target=wasm32-unknown-wasi --sysroot /wasm-sysroot "$@"

libc-test/build.rs

+69-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,67 @@ 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") => format!("union {}", t),
1900+
t if t.starts_with("__wasi") && is_struct => format!("struct {}", t),
1901+
t if t.ends_with("_t") => t.to_string(),
1902+
t if is_struct => format!("struct {}", t),
1903+
t => t.to_string(),
1904+
});
1905+
1906+
// This is an opaque struct but we go through shenanigans to define values
1907+
// for it
1908+
cfg.skip_struct(move |ty| ty == "__clockid");
1909+
1910+
cfg.field_name(move |_struct, field| {
1911+
match field {
1912+
// deal with fields as rust keywords
1913+
"type_" => "type".to_string(),
1914+
s => s.to_string(),
1915+
}
1916+
});
1917+
1918+
cfg.skip_static(move |name| {
1919+
match name {
1920+
// wasi shenanigans for defining CLOCK_REALTIME and such
1921+
s if s.starts_with("__CLOCK") => true,
1922+
_ => false,
1923+
}
1924+
});
1925+
1926+
// Looks like LLD doesn't merge duplicate imports, so if the Rust
1927+
// code imports from a module and the C code also imports from a
1928+
// module we end up with two imports of function pointers which
1929+
// improt the same thing bug have different function pointers
1930+
cfg.skip_fn_ptrcheck(|f| f.starts_with("__wasi"));
1931+
1932+
cfg.generate("../src/lib.rs", "main.rs");
1933+
}

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)