LoginSignup
7
0

More than 3 years have passed since last update.

LLVMの公式WindowsバイナリでWASMを作る

Last updated at Posted at 2019-05-11

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=<ルートディレクトリ> で指定できる。

このコマンドラインで出力される .oWASM形式になる 。このため、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さえ見せれば十分なのでオーバースペックと言える。

7
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
0