この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
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に追加しなくてもプログラムをビルドできます。
動作確認
ビルド環境ができたので、早速コンパイルして実行します。
ソース
hello.c
#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を確認してください。 ↩