Help us understand the problem. What is going on with this article?

EmscriptenでC言語をJavaScriptに変換する

More than 5 years have passed since last update.

C言語は最強のクロスプラットフォーム言語だと思っていて、
iOSもObjective-Cの中でC言語が使えるし、
AndroidもNDKでC言語が使えるので、
UI以外のロジックはすべてC言語で書けば、それはすべてのプラットフォームで使えるのではないかと思っていました。
しかし、FireFoxOSでは、それができなくて、基本JavaScriptのAPIを呼び出すという形になってC言語が使えませんでした。

失意のどん底に陥っていたのですが、
そこの打開策に、Emscriptenがあったのです!!!!

Emscriptenとは

EmscriptenはC/C++言語からLLVMを生成し、それをJavaScriptに変換するコンパイラのことです。
C言語の標準ライブラリやPOSIXの一部もサポートし、OpenGL ES2.0も使えるそうです。
Emscripten自体は下記にあります。
https://github.com/kripken/emscripten

準備(Mac OSX)

emscriptenを使えるようにします。

いろいろやってみたのですが、SDKをインストールするのが一番楽でした。

手順としては、
http://kripken.github.io/emscripten-site/docs/building_from_source/building_emscripten_from_source_using_the_sdk.html#building-emscripten-from-source-using-the-sdk
に書いてある通りやればよいです。

手順を書いておくと
https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz
から、ソースコードを取得します。

CMakeを使うので

$ brew install cmake

をしておいてください。
コードを解凍後

$  cd emsdk_portable
$ ./emsdk install sdk-incoming-64bit
$ ./emsdk activate sdk-incoming-64bit

とやればよいです。
実行にはnodeとpythonを使うっぽいので、

$ brew install node

とするのと
あとは、python2へシンボリックリンクをつくっておきます

$ sudo ln -s /usr/bin/python2.7 /usr/bin/python2

実行

$ emsdk_portable/emscripten/incoming/emcc first.c -o first.js

とすればJSに変換できます。
(emsdk_portable/emscripten/incoming/にPATHを通しておいた方がいいかも)

たとえば、

first.c
#include <stdio.h>

int
main(void)
{
  printf("Hello, World!\n");
  return 0;
}

とした場合、

$ emcc first.c -o first.js
$ node first.js
Hello, World!

となります。

Cの関数をJavaScriptから呼ぶ

例えば、

second.c
int
add(int x, int y) 
{
  return x + y;
}

という関数を外のJavaScriptから呼びたいとします。
そのときは、jsの変換のときに、

$ emcc second.c -s EXPORTED_FUCTIONS="['_add']" -o second.js

という風に公開する関数をEXPORTED_FUCTIONSで指定して上げます。
関数名には最初に"_"を加えて上げます。
あとはjs側からはccallで呼ぶことが可能セス。
ccal(関数名, 戻り値の型, [引数の型], [実際の引数])という形で使用します。

second.html
<html>
<body>
<div id="output"></div>
<script type="text/javascript" src="./second.js"></script>
<script type="text/javascript">
  var num = ccall("add", "number", ["number", "number"], [1, 2]);
  document.getElementById("output").innerHTML = num;
</script>
</body>
</html>

これで、divに3が出力されます。
また、Module.cwrapを使って関数を取り出す方法もあります。
Module.cwrap(関数名,戻り値の型, [引数の型])
という形で関数を取り出せます。

second2.html
 <html>
<body>
<div id="output"></div>
<script type="text/javascript" src="./second.js"></script>
<script type="text/javascript">
  //addという関数を取り出す
  var add = Module.cwrap("add", "number", ["number", "number"]);
  //取り出した関数を使う
  var num = add(1, 2);
  document.getElementById("output").innerHTML = num;
</script>
</body>
</html>

こちらも、divに3が出力されています。

JavaScriptをC言語から呼ぶ

逆にCのコードからJSを呼ぶときは、

mergeInto(LibraryManager.library, {
  //Cから呼ぶメソッドの定義
});

を使います。

例えば、

thirdlib.js
mergeInto(LibraryManager.library, {
    jsPower: function(x) {
        return x * x;
    }
});

というJavaScriptのファイルと

third.c
#include <stdio.h>
#include <math.h>

int jsPower(int x); //JavaScriptの関数

int 
pythagorean(x, y)
{
  //JavaScriptの関数jsPowerを呼んで計算
  return  sqrt(jsPower(x) + jsPower(y));
}

int
main(void)
{
  printf("%d\n", pythagorean(3,4));
  return 0;
}

というC言語のファイルを用意します。
そこで、--js-libraryオプションでJSコードを指定してコンパイルして実行します。

$ emcc third.c --js-library thirdlib.js -o third.js
$ node thired.js
5

きちんとJSのコードが呼ばれて計算されています。

C++の関数をJavaScriptから呼ぶ

ここからはついでなんですが、
C++にはEMSCRIPTEN_BINDINGSがつかえて、ここに登録しておくと、Module.xxxで関数を呼ぶことができます。

firstcpp.cpp
#include "emscripten/bind.h"

using namespace emscripten;
int
add(int x, int y)
{
  return x + y;
}

EMSCRIPTEN_BINDINGS(my_module) {
  function("add", &add);
}

として、以下のようにコンパイル(C++だからem++)

$ em++ firstcpp.cpp -o firstcpp.js -std=c++0x --bind

として出力したファイルを使って

firstcpp.html
<html>
<body>
<div id="output"></div>
<script type="text/javascript" src="./firstcpp.js"></script>
<script type="text/javascript">
  var num = Module.add(1, 2);
  document.getElementById("output").innerHTML = num;
</script>
</body>
</html>

とすれば3が出力されます。

その他

  • C/C++のどこまでの機能が使えるかは未調査
  • 実際にFireFoxOS アプリでどこまで使えるかは未調査

上記もやっていこうと思います。

sassy_watson
Androidアプリやフロントエンドのエンジニア。
http://sassy.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした