From c828b038b99050e81116d75726292c9a91f26799 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Wed, 7 Jun 2017 12:57:22 -0300 Subject: [PATCH 1/6] Add emscripten targets --- docker/asmjs-unknown-emscripten/Dockerfile | 20 ++++++++ docker/emscripten-entry.sh | 11 +++++ docker/emscripten.sh | 54 +++++++++++++++++++++ docker/node-wasm | 19 ++++++++ docker/node.sh | 28 +++++++++++ docker/wasm32-unknown-emscripten/Dockerfile | 24 +++++++++ src/main.rs | 18 ++++++- 7 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 docker/asmjs-unknown-emscripten/Dockerfile create mode 100755 docker/emscripten-entry.sh create mode 100644 docker/emscripten.sh create mode 100755 docker/node-wasm create mode 100644 docker/node.sh create mode 100644 docker/wasm32-unknown-emscripten/Dockerfile diff --git a/docker/asmjs-unknown-emscripten/Dockerfile b/docker/asmjs-unknown-emscripten/Dockerfile new file mode 100644 index 000000000..b812893a8 --- /dev/null +++ b/docker/asmjs-unknown-emscripten/Dockerfile @@ -0,0 +1,20 @@ +FROM ubuntu:16.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + cmake \ + gcc \ + libc6-dev \ + make \ + pkg-config + +RUN apt-get install -y --no-install-recommends python + +COPY emscripten.sh / +RUN bash /emscripten.sh + +COPY emscripten-entry.sh / +ENTRYPOINT ["/emscripten-entry.sh"] + +ENV CARGO_TARGET_ASMJS_UNKNOWN_EMSCRIPTEN_RUNNER=node diff --git a/docker/emscripten-entry.sh b/docker/emscripten-entry.sh new file mode 100755 index 000000000..6a91f8e00 --- /dev/null +++ b/docker/emscripten-entry.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e + +export HOME=/tmp/ + +cp /emsdk-portable/.emscripten $HOME/ + +source /emsdk-portable/emsdk_env.sh &> /dev/null + +exec "$@" diff --git a/docker/emscripten.sh b/docker/emscripten.sh new file mode 100644 index 000000000..3ad7dc961 --- /dev/null +++ b/docker/emscripten.sh @@ -0,0 +1,54 @@ +set -ex + +main() { + local dependencies=( + ca-certificates + cmake + curl + git + python + ) + + apt-get update + local purge_list=() + for dep in ${dependencies[@]}; do + if ! dpkg -L $dep; then + apt-get install --no-install-recommends -y $dep + purge_list+=( $dep ) + fi + done + + cd / + curl -L https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz | \ + tar -xz + cd /emsdk-portable + + ./emsdk update + ./emsdk install latest + ./emsdk activate latest + + # Make emsdk usable by any user + cp /root/.emscripten /emsdk-portable + chmod a+r -R /emsdk-portable/ + chmod a+x /emsdk-portable/emsdk + chmod a+xw /emsdk-portable/ + + # Compile and cache libc + source ./emsdk_env.sh + echo "main(){}" > a.c + emcc a.c + emcc -s BINARYEN=1 a.c + echo -e "#include \n void hello(){ std::cout << std::endl; }" > a.cpp + emcc a.cpp + emcc -s BINARYEN=1 a.cpp + rm -f a.* + chmod a+rw -R /emsdk-portable/.emscripten_cache/ + rm /emsdk-portable/.emscripten_cache.lock + + # Clean up + apt-get purge --auto-remove -y ${purge_list[@]} + + rm $0 +} + +main "${@}" diff --git a/docker/node-wasm b/docker/node-wasm new file mode 100755 index 000000000..dcfc005fb --- /dev/null +++ b/docker/node-wasm @@ -0,0 +1,19 @@ +#!/bin/bash + +path="$(dirname $1)" +file="$(basename $1)" + +# Workaround for +# https://github.com/kripken/emscripten/issues/4542 + +if [ "$(basename $path)" != "deps" ]; then + path="$path/deps" +fi + +cd "$path" + +if [ -f "$file" ]; then + /node-*/bin/node "$file" +else + /node-*/bin/node "../$file" +fi diff --git a/docker/node.sh b/docker/node.sh new file mode 100644 index 000000000..9f7f81abf --- /dev/null +++ b/docker/node.sh @@ -0,0 +1,28 @@ +set -ex + +main() { + local dependencies=( + ca-certificates + curl + ) + + apt-get update + local purge_list=() + for dep in ${dependencies[@]}; do + if ! dpkg -L $dep; then + apt-get install --no-install-recommends -y $dep + purge_list+=( $dep ) + fi + done + + cd / + curl -L https://nodejs.org/dist/v8.0.0/node-v8.0.0-linux-x64.tar.xz | \ + tar -xJ + + # Clean up + apt-get purge --auto-remove -y ${purge_list[@]} + + rm $0 +} + +main "${@}" diff --git a/docker/wasm32-unknown-emscripten/Dockerfile b/docker/wasm32-unknown-emscripten/Dockerfile new file mode 100644 index 000000000..3c8a21eaf --- /dev/null +++ b/docker/wasm32-unknown-emscripten/Dockerfile @@ -0,0 +1,24 @@ +FROM ubuntu:16.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + cmake \ + gcc \ + libc6-dev \ + make \ + pkg-config + +RUN apt-get install -y --no-install-recommends python + +COPY emscripten.sh / +RUN bash /emscripten.sh + +COPY node.sh / +RUN bash /node.sh + +COPY emscripten-entry.sh / +ENTRYPOINT ["/emscripten-entry.sh"] + +COPY node-wasm /usr/local/bin/ +ENV CARGO_TARGET_WASM32_UNKNOWN_EMSCRIPTEN_RUNNER=node-wasm diff --git a/src/main.rs b/src/main.rs index 7bd9afa61..c428c8ff5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -122,6 +122,10 @@ pub enum Target { X86_64PcWindowsGnu, I686PcWindowsGnu, + // Emscripten + AsmjsUnknownEmscripten, + Wasm32UnknownEmscripten, + // Bare metal Thumbv6mNoneEabi, Thumbv7emNoneEabi, @@ -168,6 +172,14 @@ impl Target { } } + fn is_emscripten(&self) -> bool { + match *self { + Target::AsmjsUnknownEmscripten | + Target::Wasm32UnknownEmscripten => true, + _ => false, + } + } + fn is_linux(&self) -> bool { match *self { Target::Aarch64UnknownLinuxGnu | @@ -202,7 +214,7 @@ impl Target { fn needs_docker(&self) -> bool { self.is_linux() || self.is_android() || self.is_bare_metal() || self.is_bsd() || - !self.is_builtin() || self.is_windows() + !self.is_builtin() || self.is_windows() || self.is_emscripten() } fn needs_interpreter(&self) -> bool { @@ -237,6 +249,7 @@ impl Target { Armv7LinuxAndroideabi => "armv7-linux-androideabi", Armv7UnknownLinuxGnueabihf => "armv7-unknown-linux-gnueabihf", Armv7UnknownLinuxMusleabihf => "armv7-unknown-linux-musleabihf", + AsmjsUnknownEmscripten => "asmjs-unknown-emscripten", I686AppleDarwin => "i686-apple-darwin", I686LinuxAndroid => "i686-linux-android", I686PcWindowsGnu => "i686-pc-windows-gnu", @@ -256,6 +269,7 @@ impl Target { Thumbv7emNoneEabi => "thumbv7em-none-eabi", Thumbv7emNoneEabihf => "thumbv7em-none-eabihf", Thumbv7mNoneEabi => "thumbv7m-none-eabi", + Wasm32UnknownEmscripten => "wasm32-unknown-emscripten", X86_64AppleDarwin => "x86_64-apple-darwin", X86_64PcWindowsGnu => "x86_64-pc-windows-gnu", X86_64LinuxAndroid => "x86_64-linux-android", @@ -285,6 +299,7 @@ impl Target { "armv7-linux-androideabi" => Armv7LinuxAndroideabi, "armv7-unknown-linux-gnueabihf" => Armv7UnknownLinuxGnueabihf, "armv7-unknown-linux-musleabihf" => Armv7UnknownLinuxMusleabihf, + "asmjs-unknown-emscripten" => AsmjsUnknownEmscripten, "i686-apple-darwin" => I686AppleDarwin, "i686-linux-android" => I686LinuxAndroid, "i686-pc-windows-gnu" => I686PcWindowsGnu, @@ -304,6 +319,7 @@ impl Target { "thumbv7em-none-eabi" => Thumbv7emNoneEabi, "thumbv7em-none-eabihf" => Thumbv7emNoneEabihf, "thumbv7m-none-eabi" => Thumbv7mNoneEabi, + "wasm32-unknown-emscripten" => Wasm32UnknownEmscripten, "x86_64-apple-darwin" => X86_64AppleDarwin, "x86_64-linux-android" => X86_64LinuxAndroid, "x86_64-pc-windows-gnu" => X86_64PcWindowsGnu, From 2aca86d17f05daa409bb2db4847150c3bf4e821d Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Wed, 7 Jun 2017 13:02:58 -0300 Subject: [PATCH 2/6] Add rust-itertools as build test for emscripten targets As of now, xargo cannot be build --- ci/script.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ci/script.sh b/ci/script.sh index cc582ac30..be3d97c4b 100644 --- a/ci/script.sh +++ b/ci/script.sh @@ -65,6 +65,17 @@ EOF cross build --target $TARGET popd + rm -rf $td + elif [ "$TARGET" = "asmjs-unknown-emscripten" -o \ + "$TARGET" = "wasm32-unknown-emscripten" ]; then + td=$(mktemp -d) + + git clone --depth 1 https://github.com/bluss/rust-itertools $td + + pushd $td + cross build --target $TARGET + popd + rm -rf $td else td=$(mktemp -d) From 79446d8aa8a9e50e9d5ac071f8116b6a01908b2d Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Wed, 7 Jun 2017 13:04:15 -0300 Subject: [PATCH 3/6] Add travis tests for emscripten targets --- .travis.yml | 4 +++ README.md | 74 ++++++++++++++++++++++++++++------------------------- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/.travis.yml b/.travis.yml index e70a403f9..da7cf55a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,6 +48,10 @@ matrix: - env: TARGET=x86_64-pc-windows-gnu CPP=1 STD=1 RUN=1 - env: TARGET=i686-pc-windows-gnu CPP=1 STD=1 RUN=1 + # Emscripten + - env: TARGET=asmjs-unknown-emscripten CPP=1 STD=1 RUN=1 + - env: TARGET=wasm32-unknown-emscripten CPP=1 STD=1 RUN=1 + # Bare metal - env: TARGET=thumbv6m-none-eabi RUN=1 - env: TARGET=thumbv7em-none-eabi RUN=1 diff --git a/README.md b/README.md index faa03e553..6927a44fa 100644 --- a/README.md +++ b/README.md @@ -154,41 +154,43 @@ because QEMU gets upset when you spawn several threads. This also means that, if one of your unit tests spawns several threads then it's more likely to fail or, worst, "hang" (never terminate). -| Target | libc | GCC | OpenSSL | C++ | QEMU | `test` | -|--------------------------------------|--------|-------|---------|:---:|-------|:------:| -| `aarch64-linux-android` | N/A | 4.9 | 1.0.2k | ✓ | N/A | | -| `aarch64-unknown-linux-gnu` | 2.19 | 4.8.2 | 1.0.2k | ✓ | 2.8.0 | ✓ | -| `arm-linux-androideabi` | N/A | 4.9 | 1.0.2k | ✓ | N/A | | -| `arm-unknown-linux-gnueabi` | 2.19 | 4.8.2 | 1.0.2k | ✓ | 2.8.0 | ✓ | -| `arm-unknown-linux-musleabi` | 1.1.15 | 5.3.1 | N/A | | 2.8.0 | ✓ | -| `armv7-linux-androideabi` | N/A | 4.9 | 1.0.2k | ✓ | N/A | | -| `armv7-unknown-linux-gnueabihf` | 2.15 | 4.6.2 | 1.0.2k | ✓ | 2.8.0 | ✓ | -| `armv7-unknown-linux-musleabihf` | 1.1.15 | 5.3.1 | N/A | | 2.8.0 | ✓ | -| `i686-linux-android` | N/A | 4.9 | 1.0.2k | ✓ | N/A | | -| `i686-pc-windows-gnu` | N/A | 6.2.0 | N/A | ✓ | N/A | ✓ | -| `i686-unknown-freebsd` [1] | 10.2 | 5.3.0 | 1.0.2k | | N/A | | -| `i686-unknown-linux-gnu` | 2.15 | 4.6.2 | 1.0.2k | ✓ | N/A | ✓ | -| `i686-unknown-linux-musl` | 1.1.15 | 5.3.1 | N/A | | N/A | ✓ | -| `mips-unknown-linux-gnu` | 2.23 | 5.3.1 | 1.0.2k | ✓ | 2.8.0 | ✓ | -| `mips64-unknown-linux-gnuabi64` | 2.23 | 5.3.1 | 1.0.2k | ✓ | 2.8.0 | ✓ | -| `mips64el-unknown-linux-gnuabi64` | 2.23 | 5.3.1 | 1.0.2k | ✓ | 2.8.0 | ✓ | -| `mipsel-unknown-linux-gnu` | 2.23 | 5.3.1 | 1.0.2k | ✓ | 2.8.0 | ✓ | -| `powerpc-unknown-linux-gnu` | 2.19 | 4.8.2 | 1.0.2k | ✓ | 2.7.1 | ✓ | -| `powerpc64-unknown-linux-gnu` | 2.19 | 4.8.2 | 1.0.2k | ✓ | 2.7.1 | ✓ | -| `powerpc64le-unknown-linux-gnu` | 2.19 | 4.8.2 | 1.0.2k | ✓ | 2.7.1 | ✓ | -| `s390x-unknown-linux-gnu` | 2.23 | 5.3.1 | 1.0.2k | ✓ | 2.8.0 | | -| `sparc64-unknown-linux-gnu` [2] | 2.23 | 5.3.1 | 1.0.2k | ✓ | 2.8.0 | ✓ | -| `thumbv6m-none-eabi` [3] | 2.2.0 | 5.3.1 | N/A | | N/A | | -| `thumbv7em-none-eabi` [3] | 2.2.0 | 5.3.1 | N/A | | N/A | | -| `thumbv7em-none-eabihf` [3] | 2.2.0 | 5.3.1 | N/A | | N/A | | -| `thumbv7m-none-eabi` [3] | 2.2.0 | 5.3.1 | N/A | | N/A | | -| `x86_64-linux-android` | N/A | 4.9 | 1.0.2k | ✓ | N/A | | -| `x86_64-pc-windows-gnu` | N/A | 6.2.0 | N/A | ✓ | N/A | ✓ | -| `x86_64-unknown-dragonfly` [1] [2] | 4.6.0 | 5.3.0 | 1.0.2k | | N/A | ✓ | -| `x86_64-unknown-freebsd` [1] | 10.2 | 5.3.0 | 1.0.2k | | N/A | | -| `x86_64-unknown-linux-gnu` | 2.15 | 4.6.2 | 1.0.2k | ✓ | N/A | ✓ | -| `x86_64-unknown-linux-musl` | 1.1.15 | 5.3.1 | 1.0.2k | | N/A | ✓ | -| `x86_64-unknown-netbsd`[1] | 7.0 | 5.3.0 | 1.0.2k | | N/A | | +| Target | libc | GCC | OpenSSL | C++ | QEMU | `test` | +|--------------------------------------|--------|---------|---------|:---:|-------|:------:| +| `aarch64-linux-android` | N/A | 4.9 | 1.0.2k | ✓ | N/A | | +| `aarch64-unknown-linux-gnu` | 2.19 | 4.8.2 | 1.0.2k | ✓ | 2.8.0 | ✓ | +| `arm-linux-androideabi` | N/A | 4.9 | 1.0.2k | ✓ | N/A | | +| `arm-unknown-linux-gnueabi` | 2.19 | 4.8.2 | 1.0.2k | ✓ | 2.8.0 | ✓ | +| `arm-unknown-linux-musleabi` | 1.1.15 | 5.3.1 | N/A | | 2.8.0 | ✓ | +| `armv7-linux-androideabi` | N/A | 4.9 | 1.0.2k | ✓ | N/A | | +| `armv7-unknown-linux-gnueabihf` | 2.15 | 4.6.2 | 1.0.2k | ✓ | 2.8.0 | ✓ | +| `armv7-unknown-linux-musleabihf` | 1.1.15 | 5.3.1 | N/A | | 2.8.0 | ✓ | +| `asmjs-unknown-emscripten` [4] | 1.1.15 | 1.37.13 | N/A | ✓ | N/A | ✓ | +| `i686-linux-android` | N/A | 4.9 | 1.0.2k | ✓ | N/A | | +| `i686-pc-windows-gnu` | N/A | 6.2.0 | N/A | ✓ | N/A | ✓ | +| `i686-unknown-freebsd` [1] | 10.2 | 5.3.0 | 1.0.2k | | N/A | | +| `i686-unknown-linux-gnu` | 2.15 | 4.6.2 | 1.0.2k | ✓ | N/A | ✓ | +| `i686-unknown-linux-musl` | 1.1.15 | 5.3.1 | N/A | | N/A | ✓ | +| `mips-unknown-linux-gnu` | 2.23 | 5.3.1 | 1.0.2k | ✓ | 2.8.0 | ✓ | +| `mips64-unknown-linux-gnuabi64` | 2.23 | 5.3.1 | 1.0.2k | ✓ | 2.8.0 | ✓ | +| `mips64el-unknown-linux-gnuabi64` | 2.23 | 5.3.1 | 1.0.2k | ✓ | 2.8.0 | ✓ | +| `mipsel-unknown-linux-gnu` | 2.23 | 5.3.1 | 1.0.2k | ✓ | 2.8.0 | ✓ | +| `powerpc-unknown-linux-gnu` | 2.19 | 4.8.2 | 1.0.2k | ✓ | 2.7.1 | ✓ | +| `powerpc64-unknown-linux-gnu` | 2.19 | 4.8.2 | 1.0.2k | ✓ | 2.7.1 | ✓ | +| `powerpc64le-unknown-linux-gnu` | 2.19 | 4.8.2 | 1.0.2k | ✓ | 2.7.1 | ✓ | +| `s390x-unknown-linux-gnu` | 2.23 | 5.3.1 | 1.0.2k | ✓ | 2.8.0 | | +| `sparc64-unknown-linux-gnu` [2] | 2.23 | 5.3.1 | 1.0.2k | ✓ | 2.8.0 | ✓ | +| `thumbv6m-none-eabi` [3] | 2.2.0 | 5.3.1 | N/A | | N/A | | +| `thumbv7em-none-eabi` [3] | 2.2.0 | 5.3.1 | N/A | | N/A | | +| `thumbv7em-none-eabihf` [3] | 2.2.0 | 5.3.1 | N/A | | N/A | | +| `thumbv7m-none-eabi` [3] | 2.2.0 | 5.3.1 | N/A | | N/A | | +| `wasm32-unknown-emscripten` [4] | 1.1.15 | 1.37.13 | N/A | ✓ | N/A | ✓ | +| `x86_64-linux-android` | N/A | 4.9 | 1.0.2k | ✓ | N/A | | +| `x86_64-pc-windows-gnu` | N/A | 6.2.0 | N/A | ✓ | N/A | ✓ | +| `x86_64-unknown-dragonfly` [1] [2] | 4.6.0 | 5.3.0 | 1.0.2k | | N/A | ✓ | +| `x86_64-unknown-freebsd` [1] | 10.2 | 5.3.0 | 1.0.2k | | N/A | | +| `x86_64-unknown-linux-gnu` | 2.15 | 4.6.2 | 1.0.2k | ✓ | N/A | ✓ | +| `x86_64-unknown-linux-musl` | 1.1.15 | 5.3.1 | 1.0.2k | | N/A | ✓ | +| `x86_64-unknown-netbsd`[1] | 7.0 | 5.3.0 | 1.0.2k | | N/A | | [1] For *BSD targets, the libc column indicates the OS release version from where libc was extracted. @@ -197,6 +199,8 @@ where libc was extracted. [3] libc = newlib +[4] libc = musl, gcc = emcc + ## Debugging ### QEMU_STRACE (v0.1.9+) From 1a3a59ccf28da1ae37146ae02c174d881af24685 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Thu, 8 Jun 2017 19:31:37 -0300 Subject: [PATCH 4/6] Add tests for running examples and tests --- ci/script.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ci/script.sh b/ci/script.sh index be3d97c4b..2dd3398d8 100644 --- a/ci/script.sh +++ b/ci/script.sh @@ -116,7 +116,12 @@ EOF cargo init --bin --name hello $td pushd $td + mkdir examples tests + echo "fn main() { println!(\"Example!\"); }" > examples/e.rs + echo "#[test] fn t() {}" > tests/t.rs cross run --target $TARGET + cross run --target $TARGET --example e + cross test --target $TARGET popd rm -rf $td From a016a0b2d45335b241194e6218cc994e60336da9 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Thu, 8 Jun 2017 19:32:21 -0300 Subject: [PATCH 5/6] Explain how node-wasm works --- docker/node-wasm | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/docker/node-wasm b/docker/node-wasm index dcfc005fb..3716f20a7 100755 --- a/docker/node-wasm +++ b/docker/node-wasm @@ -6,14 +6,42 @@ file="$(basename $1)" # Workaround for # https://github.com/kripken/emscripten/issues/4542 -if [ "$(basename $path)" != "deps" ]; then - path="$path/deps" -fi +# Consider a project with this struct +# ├── src +# │   ├── bin +# │   │   └── prog.rs +# │   └── lib.rs +# ├── benches +# │   └── b.rs +# ├── examples +# │   └── a.rs +# └── tests +# └── t.rs +# +# We expect that the artifacts will be generated in +# (where ? = release or debug) +# +# target/wasm32-unknown-emscripten/?/deps/ +# for tests and benches +# +# target/wasm32-unknown-emscripten/?/examples/ +# for examples +# +# target/wasm32-unknown-emscripten/?/ +# for main programs (main.rs and bin/*.rs) +# +# Because of https://github.com/kripken/emscripten/issues/4542 +# the script must be executed from where the dependencies are. -cd "$path" -if [ -f "$file" ]; then - /node-*/bin/node "$file" +base="$(basename $path)" +if [ "$base" != "deps" -a "$base" != "examples" ]; then + # main programs requeries the artifacts in $path/deps + cd "$path/deps" + exec /node-*/bin/node "../$file" else - /node-*/bin/node "../$file" + # all deps of tests, benches and examples are in $path dir + cd "$path" + exec /node-*/bin/node "$file" fi + From d1d72537a9052f205e9d1339e139e3751393f5a2 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Thu, 8 Jun 2017 19:38:47 -0300 Subject: [PATCH 6/6] Add a note about lib problems on emscripten --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6927a44fa..1734a99b9 100644 --- a/README.md +++ b/README.md @@ -199,7 +199,8 @@ where libc was extracted. [3] libc = newlib -[4] libc = musl, gcc = emcc +[4] libc = musl, gcc = emcc; Some projects that use libc may fail due to wrong + definitions (will be fixed by https://github.com/rust-lang/libc/pull/610) ## Debugging