LLVM 8.0 からは、Clangに標準でWASMターゲットが入っている。というわけで、サイトからバイナリをダウンロードしてきて、コンパイルすればWASMが出てくる。今まではツールチェーンを手でビルドする https://qiita.com/chikoski/items/41853dfb2afdec52e7d1 のが一般的な方法だったが、ビルドの再現性とかを考えると公式バイナリが有った方がありがたい。
ただし ヘッダというかライブラリが無い 。Emscriptenのを使うか、WASI SDK( https://github.com/CraneStation/wasi-sdk )のようなプロジェクトが成熟するのを待った方が良いだろう。
個人的にもコレ用のヘッダを用意しようとしていて、それは次回のエントリで。。
バイナリのダウンロード
LLVM の公式サイト( http://llvm.org/ )にダウンロードリンクがあり、 .msi 形式のインストーラがダウンロードできる。 ...zipで良いと思うんだけど。。
あと、WASMにおけるBinutilsに相当するWABTも公式バイナリが有る( https://github.com/WebAssembly/wabt/releases )ので、ツールチェイン的には揃っていると言える。
コマンドライン
適当にCMakeのToolchainファイルを書いてみた: https://github.com/okuoku/warpsdk-proto/blob/b38ad74854c2bd4f499379198691fd9c042dfc72/cmake/Modules/Platform/Yuniwarp.cmake
(今のToolchainファイルは、パスの指定を手動でやる必要があるのに注意: https://github.com/okuoku/warpsdk-proto/blob/b38ad74854c2bd4f499379198691fd9c042dfc72/cmake/protopaths.cmake#L4 FIXME: 多分ダウンロード機能とか付けた方が良いかな )
コレといって注意すべきポイントは無いが、 リンカにexport-dynamicオプションを与えないとシンボルのエクスポートができない のは微妙かもしれない。
set(WARP32_LDFLAGS "-Wl,--no-entry -Wl,--export-dynamic")
GitHubの方では wasm32-warp
を使用しているが、別に -warp
の部分は無くても良い。 (WARPは今用意しているSDKの名前)
Windowsホストのためのワークアラウンド
Toolchainファイルでは、
# Hacks
if(CMAKE_HOST_WIN32)
# CMAKE_DIAGNOSE_UNSUPPORTED_CLANG Workaround
message(STATUS "Disable Host_Win32 (WAR)")
set(CMAKE_HOST_WIN32)
endif()
# Emscripten hacks
set(CMAKE_SYSTEM_PROCESSOR x86) # We're 32bits
set(WIN32)
set(APPLE)
if(CMAKE_TOOLCHAIN_FILE)
# Do nothing, just consume the variable
endif()
のように、いくつかのCMake変数をundefしている。特に、 CMAKE_HOST_WIN32
を消しておかないと、CMakeが clang-cl
を指定しようとして間違えたものとして扱ってしまうため、正常にconfigureできなくなってしまう。
.c → .o のコマンドライン
clang.exe --target=wasm32 -o <出力> -c <入力.c>
SDKが有る場合、そのヘッダの場所は --sysroot=<ルートディレクトリ>
で指定できる。
このコマンドラインで出力される .o
は WASM形式になる 。このため、Emscriptenのような通常のWASM開発環境同様の処理をしたければ、 -emit-llvm
するなりしてLLVM bitcodeを代わりに出力し、リンク時にLTOされるようにした方が良いだろう。
リンクのコマンドライン
clang.exe -Wl,--no-entry -Wl,--export-dynamic -nostdlib --target=wasm32 -o <出力> <入力...>
--target=wasm32
オプションを指定することで、同梱の wasm-ld
コマンドを使用して1つのWASMにリンクしてくれる。
--no-entry
オプションは、 _start
関数を自動的に呼び出す挙動を抑止する。
SDKは?
この環境にはコンパイラしかないので、 printf
とか malloc
みたいな普通のC標準関数はどこか別のところから持ってくる必要がある。
今のところ、言わずと知れた Emscripten がWASMのSDKとしては最も普及しているが、今後はClang側のフロントエンドを直接利用した様々なSDKが出てくるのではないかと個人的には予想している。最も有力なのはWASI( https://wasi.dev/ )で、既にMUSLとCloudlibcベースの移植( https://github.com/CraneStation/wasi-sysroot )や、そのSDK(WASI-sdk)も動き出している。
特にWASIはnpmのような重要なプラットフォーマーが既に支持を表明し、GNU autoconfもWASIをプラットフォームとして認識する( http://lists.gnu.org/archive/html/config-patches/2019-04/msg00001.html )等それなりに実装が進んでいる。
個人的にはWASIやEmscriptenの抽象化はWASMのポテンシャルを生かすには不十分だと思っていて、もうちょっと用途を絞ったプロファイルを複数用意するのが良いと考えている。例えば、WASIでは fd
を直接アプリケーションに見せているが、ゲームを配布するような目的であればSDLの各種APIさえ見せれば十分なのでオーバースペックと言える。