EmscriptenでC言語実装のHelloWorldを動かしてみた
はじめに
EmscriptenはLLVMのコードをJavaScriptに変換するコンパイラです。 C/C++で実装されたプログラムやライブラリをJavaScriptに変換することで、 Node.jsやブラウザ環境で利用できるようになります。
今回はEmscriptenを導入して、Node.jsでC言語実装のHello worldを動かしてみました。
検証環境
- macOS Sierra 10.12.6
- Emscripten 1.37.16
- Python 2.7.13
- Node.js 8.3.0
- JRE 1.8.0
Emscriptenのインストール
まずEmscripten SDKをインストールしましょう。 以下のページで各環境向けのSDKが提供されています。 Download and install -- Emscripten
macOSの場合はポータブル版をインストールします。 環境ごとに前提条件が異なるので、詳細は Platform-specific notes を確認してください。 macOSの場合は以下のツールが必要です。
- Xcode Command Line Tools
- git
- CMake
- Node.js
- JRE
emsdk-portableのemsdkコマンドでインストールします。
$ # emsdk-portableのダウンロード $ wget https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz $ tar -xvf emsdk-portable.tar.gz $ cd emsdk-portable $ # 利用可能なSDKの一覧を取得 $ ./emsdk update $ # 最新版をインストール $ ./emsdk install latest $ # 最新版を使用するように設定 (ここで設定ファイル ~/.emscripten が生成される) $ ./emsdk activate latest $ # Emscriptenを使用するための環境変数を設定する $ source ./emsdk_env.sh $ # Emscriptenのバージョンを確認する $ emcc --version emcc (Emscripten gcc/clang-like replacement) 1.37.16 () Copyright (C) 2014 the Emscripten authors (see AUTHORS.txt) This is free and open source software under the MIT license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
ここまででインストールは完了です。
emsdk_env.shを読み込むと、Emscripten用のclangやNode.jsがPATHに追加されます。 ターミナルを再起動せずに他のプログラムをビルドするとエラーになることがあるので注意しましょう。 EmscriptenのツールのみPATHに追加することをおすすめします。
※ ~/.emscripten にEmscripten用のLLVM/clang、Node.jsのパスが記録されているので、 PATHに追加しなくてもプログラムをビルドできます。
動作確認
ビルド環境ができたので、早速コンパイルして実行します。
ソース
#include <stdio.h> /* for printf */ int main(int argc, char** argv) { printf("%s\n", "Hello, world!"); return 0; }
ビルド & 実行
生成されたJavaScriptのコードを確認しやすくするため、最適化なし(-O0)でコンパイルします。
$ emcc -o hello.js -O0 hello.c $ node hello.js Hello, world!
Emscriptenが出力するコードは、asm.jsと呼ばれるJavaScriptのサブセットで記述されています。 hello.jsのmain関数を確認してみましょう。「_main」で検索するとヒットします。
function _main($0,$1) { $0 = $0|0; $1 = $1|0; var $2 = 0, $3 = 0, $4 = 0, $vararg_buffer = 0, label = 0, sp = 0; sp = STACKTOP; STACKTOP = STACKTOP + 16|0; if ((STACKTOP|0) >= (STACK_MAX|0)) abortStackOverflow(16|0); $vararg_buffer = sp; $2 = 0; $3 = $0; $4 = $1; (_printf(384,$vararg_buffer)|0); STACKTOP = sp;return 0; }
スタックを管理して関数呼び出し、といったまさにアセンブラのようなコードですね。
おまけ
出力ファイルの拡張子を.html にすると、ブラウザで実行できるHTMLを出力します。
$ emcc -o index.html hello.c $ python -m SimpleHTTPServer Serving HTTP on 0.0.0.0 port 8000 ...
http://localhost:8000/index.html
にアクセスするとブラウザで実行できます。
Hello, world!と表示されていますね。
おわりに
C言語で実装したプログラムをJavaScriptに変換して、Node.jsで実行することができました。 WEBのクライアントサイドとは縁が薄そうなC言語ですが、 Emscriptenを使うとブラウザで動くプログラムを作れます。1
この言語にしか無いライブラリをブラウザ環境で使いたい! リリースされたばかりでJavaScript向けのバインディングが用意されていない! 上手くいけば、こういった課題を解消できるかもしれないですね。
- ソケット通信やファイルシステムなど制限があります。 詳細は公式ドキュメントのCode Portability and Limitationsを確認してください。 ↩