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を通しておいたほうがいいかも)
たとえば、
#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から呼ぶ
例えば、
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(関数名, 戻り値の型, [引数の型], [実際の引数])という形で使用します。
<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(関数名,戻り値の型, [引数の型])
という形で関数を取り出せます。
<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から呼ぶメソッドの定義
});
を使います。
例えば、
mergeInto(LibraryManager.library, {
jsPower: function(x) {
return x * x;
}
});
というJavaScriptのファイルと
#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で関数を呼ぶことができます。
#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
として出力したファイルを使って
<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 アプリでどこまで使えるかは未調査
上記もやっていこうと思います。