EmscriptenでC言語実装のHelloWorldを動かしてみた

2017.08.17

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

EmscriptenLLVMのコードを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 にアクセスするとブラウザで実行できます。

ss-emscripten-hello-world-html

Hello, world!と表示されていますね。

おわりに

C言語で実装したプログラムをJavaScriptに変換して、Node.jsで実行することができました。 WEBのクライアントサイドとは縁が薄そうなC言語ですが、 Emscriptenを使うとブラウザで動くプログラムを作れます。1

この言語にしか無いライブラリをブラウザ環境で使いたい! リリースされたばかりでJavaScript向けのバインディングが用意されていない! 上手くいけば、こういった課題を解消できるかもしれないですね。


  1. ソケット通信やファイルシステムなど制限があります。 詳細は公式ドキュメントのCode Portability and Limitationsを確認してください。