Skip to content

Commit 899c5e6

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 899c5e6

File tree

6 files changed

+948
-6
lines changed

6 files changed

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

ci/run-docker.sh

+6-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ run() {
99
echo "Building docker container for target ${1}"
1010

1111
# use -f so we can use ci/ as build context
12-
docker build -t libc -f "ci/docker/${1}/Dockerfile" ci/
12+
DOCKER_BUILDKIT=1 \
13+
docker build \
14+
--ssh default \
15+
-t libc \
16+
-f "ci/docker/${1}/Dockerfile" \
17+
ci/
1318
mkdir -p target
1419
if [ -w /dev/kvm ]; then
1520
kvm="--volume /dev/kvm:/dev/kvm"

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)