前回の続き。
とりあえず汎用インタフェースとしての整形はまだだけど、emscripten版proj.4のクライアントサイドJavaScriptでnadgridsファイル読めるようになりました。
その調査に使った小ネタ集。
stdoutを確認したい時は自前で準備
[追記4/29]:こちら、最新のemscripten 1.16.0に差し替えてみるとprintfの結果が自動でConsole.logに出るようになっていました。デフォルトのstdout処理がついたようです。
cソースコードにデバグ用にprintf加えても、emscriptenコンパイルしていくら実行しても、JavaScriptコンソール等には出力されません。
これは、stdoutからJavaScriptに処理を持ってくる繋ぎの実装が必要でした。
stdoutだけでなく、stdin, stderrも同様のようですね。
例えば下記のような。
Module['stdout'] = function(x) {
console.log(String.fromCharCode(x));
};
これだと、一文字ずつ表示されてしまうので、Console上では縦に文字列が並んでしまいますが、デバグ用ならそれで十分なのでそうやってました。
奇麗に表示したいなら、改行までバッファして改行後に出力とかの工夫が必要でしょう。
--pre-jsあるいは--post-jsで指定するファイルあたりに組み込んでおくと、コンパイル後いちいち入れなくて済むので便利です。
実行前に環境変数を変更したい時
JSコンパイルされたcコード部分に認識させる環境変数を定義したい時は、以下のような感じで与えられます。
Module.preRun.push(function() {ENV.PROJ_LIB = "nadgrids"});
これも--pre-jsに入れておけば便利ですが、実行前に入れておかないといけない分、--post-jsでもいいのかは不明です(試してません)。
仮想ファイルシステム内にファイルを埋め込む(コンパイル時)
下記のようなコンパイルオプションで、コンパイル結果のJSの中にファイルを埋め込めます。
$(EMCC) $(MINIMIZE) $(CFLAGS) $(PROJ4_SRCDIR)src/.libs/libproj.dylib --embed-file nadgrids/conus --embed-file nadgrids/alaska --embed-file nadgrids/ntv2_0.gsb --embed-file nadgrids/ntv1_can.dat --pre-js js/emproj/pre.js --post-js js/emproj/post.js -o js/emproj.js -s EXPORTED_FUNCTIONS="['_strlen','_free','_strncpy','_pj_init_plus','_memset','_malloc','_pj_transform','_memcpy', '_strcpy','_pj_is_latlong','_pj_free']"
--embed-fileのオプションですね。
でっかいファイルを埋め込むと、当然ながら生成されるJSもモリモリ太ります。
仮想ファイルシステム内にファイルを埋め込む(JavaScript実装内)
で、上記--embed-fileオプションをつけるとどうなるかというと、ソースファイルのJSコンパイル結果の前に、下記のような実装が付加されます。
var Module;
if (typeof Module === 'undefined') Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()');
if (!Module.expectedDataFileDownloads) {
Module.expectedDataFileDownloads = 0;
Module.finishedDataFileDownloads = 0;
}
Module.expectedDataFileDownloads++;
(function() {
function runWithFS() {
function assert(check, msg) {
if (!check) throw msg + new Error().stack;
}
Module['FS_createPath']('/', 'nadgrids', true, true);
Module['FS_createDataFile']('/nadgrids', 'conus', [67, 84, 65, 66, 76, ...], true, true);
}
if (Module['calledRun']) {
runWithFS();
} else {
if (!Module['preRun']) Module['preRun'] = [];
Module["preRun"].push(runWithFS); // FS is not initialized yet, wait for it
}
})();
多分、仮想ファイルシステムの初期化と、フォルダ生成、ファイル生成あたりをやってるものと思われます。
FS_createPathでフォルダ生成、FS_createDataFileでファイル生成。
ただこれ、--embed-fileオプションで埋め込むと、バグがあるのか、せっかく--pre-js/--post-jsで囲んでAMDインタフェース作ってても、その前(--pre-jsより前)に付加されてしまいます。
なのでそのままだといくらやってもうまくいかず、手作業編集でAMDインタフェース内に移動してやらないといけない。
また、前述の通り、--embed-fileオプションで埋め込むとJSが馬鹿太りしてしまうので、この一連の定石テクニックだけもらって、実運用時は
Module.expectedDataFileDownloads++;
あたりまでを--pre-js、それ以降からファイル生成あたりを抜いたものを--post-jsに埋め込んでやって、またFS_createDataFileは外部からも叩けるインタフェースを作り、後から必要なファイルを非同期で追加できるようにしておいてやるのがいいのかな、と思います。
仮想ファイルシステム上のディレクトリ構成
基本、/ がカレントディレクトリとして扱われる模様です。
ですので、/nadgrids/conus にファイルを作れば、フルパス指定しなくても nadgrids/conus でアクセスできます。
そのくらいです。
参考になりましたら…。
[追記]
うおおおおおおお神エントリ発見。
Emscriptenでファイルを読み込むソースをJavaScriptに変換するには
というかストックしてたのに全く気付いてなかった。
ストックしてた時点ではあまりよく意味理解してないままに、emscriptenだというだけでストックしてたのかな…。