WSLを使ってC++をEmscriptenでWebAssemblyにコンパイルしたい


目標

WSLを使ってC++をEmscriptenでWebAssemblyにコンパイル

環境

Windows 10 Home

方法

1. WSLを有効,Ubuntuのインストール

1.1 WSLを有効にする

コントロールパネル > プログラム > Windowsの機能の有効化または無効化
Windows Subsystem for LINUXにチェックを入れる

1.2 Ubuntuのインストール

Microsoft Storeを開いてUbuntuと検索
3つくらい似た名前のソフトがヒットしましたが,僕は無印のUbuntuをインストールしました

1.3 ホームディレクトリを変更する

Windows側からWSL側のディレクトリにアクセスするのが非常に面倒だったのでC:直下にubuntu_homeディレクトリを作ってそちらにホームディレクトリを変更しました
やりかたは【WSL】Ubuntuのホームディレクトリを変更する _ IT土方の奮闘記を参考にしました
めっちゃわかりやすい

2. Emscriptenのインストール

2.1 インストール

基本的に公式チュートリアル通りにやったので使ったコマンドだけ書いておきます

Shell
$ git clone https://github.com/emscripten-core/emsdk.git
$ cd emsdk
$ ./emsdk install latest
$ ./emsdk activate latest

2.2 PATHを通す

いつでもどこでもemccコマンドを呼びたいのでパスを通します

試しに

Shell
$ source ./emsdk_env.sh

と入力するとこんな感じで追加するPATHや環境変数が返ってきます

Shell
Adding directories to PATH:
PATH += /{user}/c/ubuntu_home/Projects/emsdk
PATH += /{user}/c/ubuntu_home/Projects/emsdk/upstream/emscripten
PATH += /{user}/c/ubuntu_home/Projects/emsdk/node/12.9.1_64bit/bin

Setting environment variables:
EMSDK = /{user}/c/ubuntu_home/Projects/emsdk
EM_CONFIG = /{user}/c/ubuntu_home/.emscripten
EM_CACHE = /{user}/c/ubuntu_home/Projects/emsdk/upstream/emscripten/cache
EMSDK_NODE = /{user}/c/ubuntu_home/Projects/emsdk/node/12.9.1_64bit/bin/node

まず/{user}/c/ubuntu_home内の.profileをVisual Codeなどのエディタで開いて一番下あたりにこれらを追記していく

.profile
# For Emscripten
# Adding directories to PATH:
PATH="/{user}/c/ubuntu_home/Projects/emsdk:$PATH"
PATH="/{user}/c/ubuntu_home/Projects/emsdk/upstream/emscripten:$PATH"
PATH="/{user}/c/ubuntu_home/Projects/emsdk/node/12.9.1_64bit/bin:$PATH"
# Setting environment variables:
EMSDK="/{user}/c/ubuntu_home/Projects/emsdk"
EM_CONFIG="/{user}/c/ubuntu_home/.emscripten"
EM_CACHE="/{user}/c/ubuntu_home/Projects/emsdk/upstream/emscripten/cache"
EMSDK_NODE="/{user}/c/ubuntu_home/Projects/emsdk/node/12.9.1_64bit/bin/node"

最初そのままコピペしたんだけどうまくいかなくて

  • =前後のスペースを消す
  • 中身を""で囲う
  • PATHは最後に:$PATHをダブルクォーテーションの前に付け足す

てことをやったらうまくいきました.
シェルを再起動して

Shell
$ emcc -v

が通ればOK!

3. EmscriptenでCをコンパイル

コンパイル

公式チュートリアルにもあるようにまずはシンプルなCファイルのコンパイルからやってみた

以下のファイルを作成
作業用フォルダとして適当にtest_emsdkを作ってそこに保存していく

test_emsdk/hello.c
#include <stdio.h>
int main(int argc, char *argv[]){
  printf("Hello, world!\n");
  return 0;
}

以下のコマンドでコンパイル

Shell
$ emcc hello.c -s WASM=1 -o hello.html

-s WASM=1で出力をWASMに指定して
-o hello.htmlでコードを実行するためのHTMLを指定している

うまくいけばhello.cと同じ階層に以下のファイルが生成される

  • hello.html
  • hello.js
  • hello.wasm

さっそくhello.htmlをブラウザで開いてみる
今回はChromeを使った

エラー

開けなかった

公式チュートリアルにこんなことが書いてあった

要するにXHRリクエストに対応してないからローカルのwebサーバーを立ち上げてそこで開く必要があるらしい

というわけでNode.jsを使ってローカルサーバーを起動します

4. WSLにNode.jsをインストール

apt-getを使うと古いバージョンがインストールされるとかっていう噂を見かけたので別のやり方でやりました
WSL install Node
ここにまさにやりたいことがドンピシャで書いてあったので丸々参考にした

まず,
nvm-sh_nvm_ Node Version Manager - POSIX-compliant bash script to manage multiple active node.js versions
ここのページのInstall & Update Scriptの項目に書かれている

Shell
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash

をホームディレクトリにて実行.(バージョンが変わってるかもしれないので実際に上のページに行ってコピペすることを推奨します)

次に以下のコマンドを実行してインストール

Shell
$ source ~/.bashrc      // バッシュの再読み込み
$ nvm install node      // nodeのインストール

確認

Shell
$ node --version
v14.2.0

OK!

5. 簡易的にローカルサーバー起動

http-serverというものを使えばお手軽にサーバー起動できるみたいなので採用してみた

インストール

Shell
$ npm install -g http-server

起動
作業用のtest_emsdkディレクトリ上で以下のコマンドを実行

Shell
$ http-server -o

この-oオプションをつけると起動後自動的にブラウザを開いてくれる

6. あらためてhello.htmlを開く

今しがたhttp-serverで起動したサーバーからhello.htmlにアクセス

今度はうまくいった!!

次の目標

本来の目標である複数cppファイルのコンパイルとかやりたい

参考