EmscriptenでRustをJSへコンパイルする (コンパイルできてない)

2016/3/8追記

うまくいきました。エントリ書きました。

gifnksm.hatenablog.jp


RustでEmscriptenを使う方法を調べたのでメモ。2015年12月28日時点でなんとか動作させるための手順です。今後オフィシャルにEmscriptenサポートが入るなどすると、もっと簡単なやり方になるかと思います。

Emscripten SDK をインストール

Emscriptenのサイト から Emscripten SDK をダウンロードしてきて、インストールします。

$ wget https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz
$ tar xvf emsdk-portable.tar.gz
$ cd emsdk_portable
$ ./emsdk update
$ ./emsdk install latest
$ ./emsdk activate latest

Emscripten 対応の rust をコンパイル

brson/rustemscripten ブランチをクローン。

$ git clone git@github.com:brson/rust.git -b emscripten

なお、12/28時点でのコミットのハッシュは c42f32e です。

当該ブランチの src/llvm submodule は rust-lang のものが読み込まれていますが、ハッシュ値emscriptenLLVM fork (emscripten-fastcomp) のものとなっていますので、以下の変更を加えます (.gitmodules のコミット漏れ?)

diff --git a/.gitmodules b/.gitmodules
index 83be070..5f92864 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,6 @@
 [submodule "src/llvm"]
    path = src/llvm
-  url = https://github.com/rust-lang/llvm.git
+   url = https://github.com/kripken/emscripten-fastcomp.git
    branch = master
 [submodule "src/compiler-rt"]
    path = src/compiler-rt

ここまで準備できたらいよいよ configure & make です。以下の作業が必要なようです。

$ source <path to SDK>/emsdk_env.sh
$ ./configure --target=asmjs-unknown-emscripten
$ make -j4

なお、手元の OSX 環境では configure に失敗するため、EmscriptenのIssueコメントを参考にし、 CC=gcc CXX=g++環境変数を指定して configure したところ、うまく動作しました (デフォルトコンパイラが clang の環境でEmscripten 側の clang が使われてしまうとだめなのかもしれません)。

configure: error: C preprocessor "/lib/cpp" fails sanity check

hello world! のコンパイル

謎のエラーが出て通らず。。。

$ LD_LIBRARY_PATH=../rust-emscripten-c42f32e/x86_64-unknown-linux-gnu/stage2/lib/ ../rust-emscripten-c42f32e/x86_64-unknown-linux-gnu/stage2/bin/rustc ./main.rs --target asmjs-unknown-emscripten
error: linking with `emcc` failed: exit code: 1
note: "emcc" "-L" "/home/nksm/tmp/rust-emscripten-c42f32e/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib" "main.0.o" "-o" "main.js" "-Wl,--gc-sections" "-nodefaultlibs" "-L" "/home/nksm/tmp/rust-emscripten-c42f32e/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib" "-Wl,-Bstatic" "-Wl,-Bdynamic" "/home/nksm/tmp/rust-emscripten-c42f32e/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/libstd-ca1c970e.rlib" "/home/nksm/tmp/rust-emscripten-c42f32e/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/libcollections-ca1c970e.rlib" "/home/nksm/tmp/rust-emscripten-c42f32e/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/librustc_unicode-ca1c970e.rlib" "/home/nksm/tmp/rust-emscripten-c42f32e/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/librand-ca1c970e.rlib" "/home/nksm/tmp/rust-emscripten-c42f32e/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/liballoc-ca1c970e.rlib" "/home/nksm/tmp/rust-emscripten-c42f32e/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/liballoc_system-ca1c970e.rlib" "/home/nksm/tmp/rust-emscripten-c42f32e/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/liblibc-ca1c970e.rlib" "/home/nksm/tmp/rust-emscripten-c42f32e/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/libcore-ca1c970e.rlib" "-l" "c"
note: error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
error: Unknown attribute kind (45)
Traceback (most recent call last):
  File "/home/nksm/dev/emsdk_portable/emscripten/master/emcc", line 1309, in <module>
    final = shared.Building.llvm_opt(final, link_opts, DEFAULT_FINAL)
  File "/home/nksm/dev/emsdk_portable/emscripten/master/tools/shared.py", line 1471, in llvm_opt
    assert os.path.exists(target), Failed to run llvm optimizations:  + output
AssertionError: Failed to run llvm optimizations:

error: aborting due to previous error

うーん、なんでしょうこれは。