はじめに
Emscripten をやってみたくなってきたので CLion (JetBrains の C/C++ 用 IDE) で環境作りをしてみました。
記事作成時に使ったものは下記の通りです。
- Windows 10
- CLion 2019.1
- Emscripten 1.38.28 (NodeJS 8.9.1)
- NodeJS 11.13.0
- Chrome 73.0.3683.103
- Firefox 66.0.2
準備
Emscripten SDK のインストール
Windows 10 では WSL に Linux 版を入れるようですが、手元の WSL では emcc がうまく動いてくれなかったので普通に Windows 上に入れます。 CLion は WSL 上のコンパイラを Toolchain として使うこともできるので、問題ないなら WSL でやるのもよいかもです。
"Windows 7 and earlier installation" では zip のダウンロードをして展開となっていますが、 Linux の手順と同じように GitHub から clone してやった方がよいように思います。
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
emsdk install latest
emsdk activate latest
emsdk の実行には Python 環境が別途必要です。
"emsdk_env.bat" はコンソールで emsdk を使う時だけ実行すればよいです。 CLion 上で使う場合は必須ではないです。
CLion のインストール
- CLion は普通にインストーラーを落としてきてインストールします。
- Toolchain として MinGW をインストールします。
CLion の設定
- "Settings" を開きます。
- "Build, Execution, Deployment - Toolchains" で MinGW の設定をします。
- "Appearance & Behavior - Path Variables" を開き、 Emscripten SDK が設定する環境変数の "EMSCRIPTEN" を同じように CLion 側に設定します (この変数だけ後で使う) 。
- "Plugins" で "NodeJS" プラグインをインストールします。
実際に Emscripten をやってみる
プロジェクト作成
- CLion を起動し、 "New Project" から "C++ Executable" を選択、適当に作成する。
- とりあえずビルドして動くかどうか確認する。
Emscripten 用のビルド設定をする
- "File - Settings" で環境設定を開きます。
- "Build, Execution, Deployment - CMake" を選択します。
- "CMake options" に Emscripten の Toolchain ファイル (Emscripten.cmake) を指定します。ここで先に指定した "EMSCRIPTEN" を使います。
-DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake
これで一回ビルドします。
Emscripten 用の実行設定をする
- ツールバー上にある実行環境を切り替えるドロップダウンメニューをクリックすると、リストの一番上に "Edit Configulations..." を選択します。
- ダイアログのツールバーの "+" ボタンを押し、 "Node.js" を選択します。
- "Node interpreter" で実行に使う node の実行ファイルを選択します。単独で NodeJS のインストールをしていないのであれば、 Emscripten SDK が持っているものを使っても OK です (ちょっと古いようですが wasm は動くのでとりあえずは問題ないかと) 。
- "Working directory" にプロジェクトのディレクトリを指定します。
- "JavaScript file" でビルドで生成された .js ファイルを指定します。 (Debug ビルドだったらおそらくは cmake-build-debug の中)
ビルドとプログラムの実行
通常はビルド設定とデバッグ (実行) 設定は同一のものになるのですが、今回の場合はビルドは CMake (C++) でデバッグが NodeJS (Java Script) と異なっているので要注意です。ビルド時と実行時で切り替えるか、設定は NodeJS にしてビルドは常に All で行うかどちらかにしてください。
デバッグ
かなりはまりました。
結論的には今のところは通常の gcc/clang でネイティブビルドしてデバッグし、一通りできたら Web に持って行く方が無難そうです。
NodeJS
先に行った CLion の NodeJS デバッグ設定をする事で CLion からのデバッグ実行は可能でした。が、 C++ ソースへのブレイクはできませんでした (wasm のアセンブリコードしか見えない) 。 Java Script 部分にはブレイクポイントが設置できるのでブレイク可能です。
コンパイルオプションに -g4 を指定すると source map が作成されますが、作成しても見えるようになりませんでした (--source-map-base も関係なかった) 。 CMakeLists.txt に書くなら次のようにします。
if (EMSCRIPTEN)
set(CMAKE_CXX_FLAGS_DEBUG "-g4")
endif()
Chrome
ビルド出力ファイルを html にしてブラウザから開くとブラウザの Java Script エンジンで実行でき、ブラウザのデバッガも使えます。
if (EMSCRIPTEN)
set(CMAKE_CXX_FLAGS_DEBUG "-g4")
set(CMAKE_EXECUTABLE_SUFFIX ".html")
endif()
CMakeLists.txt に上記定義をしてビルド。コンソールから emrun で簡易 Web サーバーを起動します。 (emsdk_env.bat を実行しておいてください)
emrun --no_browser --port 8080 .
Chrome で http://localhost:8080/ からビルド結果の html にアクセスすると実行されます。開発者ツールからデバッガでブレイクする事もできますが、ここでも C++ 部分はソースコードでアクセスできませんでした。
・・・が、 CMake を使わず直接 emcc でビルドしたものにアクセスすると C++ コードに対してデバッガでブレイクできました。
emcc -g4 -o HelloWorld.html main.cpp
この二つのビルド結果を見比べるとビルド結果に含まれるマップ情報のパス名に違いがあり、 emcc の場合はファイル名しかないのに CMake でビルドしたものはフルパスで書き込まれていました。また、大きな違いとして map ファイルの "sources" に書かれているファイル名が CMake ビルドのものだとおかしくなっている というのがありました。
"sources":["D","C"]
"sources":["main.cpp","C"]
D や C ってなっているのは多分ドライブレターで、この後 : が続くために正しく処理できなくなっているのではないかと想像します。なので Mac や Linux だったら問題にならないかもしれないです。
emcc で直接ビルドした版でも NodeJS では C++ コードへのブレイクはできませんでした。
Firefox
Chrome と同様の事をしても C++ コード内でのブレイクはできませんでした (Firefox の設定で source map は有効にしています) 。Java Script 部分はブレイク可です。
おわりに
今回の記事は結局のところ
- Emscripten SDK + CMake でビルド
- NodeJS で実行、デバッグ
をしているだけなので CLion である必要性はないですが、 CLion でやると手順がわかっていれば割と簡単に (手数が少なく) 環境組めるしエディッターも便利なのでなかなよいと思います。 VS Code の方が実は便利だったりするのかなあという気もしなくはないので折を見てそっちもやってみたいところ。
最近 WebAssebly Studio というブラウザ用の IDE が発表されました。将来的には有力な選択肢になるのかなあと思いますが現状ではまだまだなので今後の進化に期待でしょうか。
JetBrains の IDE はこれまであんまりしっくり来なかったのですが、 CLion は結構いい感じで使いやすかったのでこれから積極的に使っていきたいところです。 Emscripten も標準でサポートして欲しいですね。