はじめに
JavaScriptCore (WebKit/Safari の JavaScript エンジン) を C 言語に組込む方法を調べてみました。
解説はソースコード中のコメントを見てください。
まず
以下のコードを hoge.c とかいう名前で保存します。
#include <JavaScriptCore/JavaScriptCore.h> static JSValueRef jsGlobalPrint( JSContextRef ctx, JSObjectRef jobj, JSObjectRef jobjThis, size_t argLen, const JSObjectRef args[], JSValueRef* jobjExp); int main(int argc, char** argv) { if (argc == 1) exit(0); // ---- グローバルの環境の準備 ---- // グローバル実行コンテキストというものを作る JSGlobalContextRef ctx = JSGlobalContextCreate(NULL); // グローバル実行コンテキストが持つグローバルオブジェクトを取得する // ブラウザでいうところの window オブジェクトのようなもの JSObjectRef jobjGlobal = JSContextGetGlobalObject(ctx); // ---- print 関数を作る ---- // JavaScript で扱える文字列を作る JSStringRef jstrPrint = JSStringCreateWithUTF8CString("print"); // C の関数を JS の関数オブジェクトにする JSObjectRef jfuncPrint = JSObjectMakeFunctionWithCallback(ctx, jstrPrint, (JSObjectCallAsFunctionCallback)jsGlobalPrint); // グローバルオブジェクトのプロパティとして追加 JSObjectSetProperty(ctx, jobjGlobal, jstrPrint, jfuncPrint, kJSPropertyAttributeNone, NULL); // 文字列のリファレンスカウンタをデクリメント JSStringRelease(jstrPrint); // JavaScript のソースを JS の文字列にする JSStringRef jstrSource = JSStringCreateWithUTF8CString(argv[1]); // 実行、 this を NULL とするとグローバルオブジェクトが this になるらしい JSEvaluateScript(ctx, jstrSource, NULL, NULL, 0, NULL); // 訂正: 0 ではなく 1 が正しいです。(開始行数、詳しくは次の記事を見てください><) // 文字列のリファレンスカウンタをデクリメント JSStringRelease(jstrSource); // 解放してもいいよ JSGlobalContextRelease(ctx); // 解放するよ JSGarbageCollect(ctx); return 0; } static JSValueRef jsGlobalPrint( JSContextRef ctx, JSObjectRef jobj, JSObjectRef jobjThis, size_t argLen, const JSObjectRef args[], JSValueRef* jobjExp) { if (argLen) { // 第一引数を JS の文字列としてコピー JSStringRef jstrArg = JSValueToStringCopy(ctx, args[0], jobjExp); // 長さを取得 size_t len = JSStringGetMaximumUTF8CStringSize(jstrArg); // 領域の確保 char* szArg = (char*)malloc(len); // 領域に UTF8 をコピー JSStringGetUTF8CString(jstrArg, szArg, len); // 出力 puts(szArg); // 文字列のリファレンスカウンタをデクリメント JSStringRelease(jstrArg); // 解放 free(szArg); } // undefined を作って返す return JSValueMakeUndefined(ctx); }
コンパイル
Mac だと、以下のように -framework で JavaScriptCore を指定すればコンパイルできます。
$ gcc hoge.c -framework JavaScriptCore $
簡単ですね!
JavaScriptCore って普通の Mac OS X の環境でも入ってるんだろうか><誰か教えて><
(Safari が動いている = JavaScriptCore.framework が使えるという認識で良い?)
Windows や他の Unix でのやり方はわかりません><
a.out を実行
$ ./a.out "var data = {3:'さん',6:'ろく',9:'きゅう'}; for (var i = 1; i <= 10; i++) print(i%3?i:data[i])" 1 2 さん 4 5 ろく 7 8 きゅう 10 $
おおおおお。ちゃんと動いてますね!