non vorrei lavorare

昔はおもにプログラミングやガジェット系、今は?

Emscriptenでファイルを読み込む

こんにちは、先日、二男の保育園入園を契機に長男、次男の登園時の負担を経緯減すべく、ママチャリを2駅さきの最寄りのホームセンターに買いに行き、さっそく帰りは長男とご機嫌に自転車で帰宅しました。長男は、自転車が気に入ったようです。@kjunichiです。
 

背景

OpenGLなソースをEmscriptenJavaScriptに変換できることは分かったのだが、OpenGLなソースだとテクスチャーをファイルとして読み込むようなケースが多々ある、Emscriptenでこういったファイルの読み込みも可能なような記述があるが、具体的な方法が英語力の低さから分からずにいた。

そんな折、はてなの人力検索ですばらしい質問と回答を発見して、これを手がかりにC++でファイルを読み込むプログラムをEmscriptenJavaScriptに変換することが出来た。

前提

EmscriptenJavaScriptに変換された本体のプログラムのファイルアクセスは仮想ファイルシステムを介して行われる。

この為、本体のプログラムを実行する前に、この仮想ファイルシステムに必要なファイルやフォルダの登録が必要となる模様。

emscriptenのページでは自動でやってくれるやり方もあるようだが、このやり方だと、ファイルの内容がコンパイル時に埋め込まれてします。(まぁ、別ファイルにできるので、こちらを後から変更できそうだが。。)

C/C++のソース中でファイル名を指定して読んでいる場合、FS.createPreloadedFileを使うと対応できる。

また、前処理内で、動的にデータを作成してしまうAPIも用意されている模様。

対象のファイルはemccを実行するディレクトリを/としてJavaScript側では扱われる模様(絶対パス指定ならそのままのパスで扱われる模様)

同名ファイルでフォルダが違うファイルを読み込むサンプル

C++のソース

#include <fstream>
#include <iostream>

using namespace std;

int
main (int argc, char **argv)
{
  string line;
  ifstream fin ("./input.txt");
  while (getline (fin, line))
    {
      cout << line << endl;
    }
  fin.close ();
  fin.open ("data/input.txt");
  while (getline (fin, line))
    {
      cout << line << endl;
    }
  fin.close ();

  return 0;
}

 

前処理用のJavaScriptソースの準備

 

前処理のJavaScriptでやり事は以下

 

 



前処理用のJavaScript

 

Module['preRun'] = function () {
    FS.createFolder(
        '/',
        'data',
        true,
        true
    );
    FS.createPreloadedFile(
        '/',
        'input.txt',
        '/input.txt', // httpでアクセスする際のURLを指定
        true,
        false
    );
    FS.createPreloadedFile(
        '/data',
        'input.txt',
        '/data/input.txt',   // httpでアクセスする際のURLを指定
        true,
        false
    );
};

--pre-jsを指定してhtmlファイルを作成

emcc target.cpp -o target.html --pre-js pre.js

読み込まれるファイルの用意

 

echo "hogehoge" > input.txt
mkdir data
echo "foobar">data/input.txt

 

HTTPサーバを立てる

 

pre.jsのFS.createPreloadedFileでXMLHttpRequestを内部的に読んでいるので、ローカルのファイルといえどもWebサーバーを介してのアクセスが必要です。

 

Emscriptenな環境ではPythonが入っているので、SimpleHTTPServerでさくっとWebサーバーを立ち上げて試せます。

python -m SimpleHTTPServer 8000

ブラウザでアクセスしてみる

 

emccのコンパイルがうまくいっても安心できません。pre.jsで仮想ファイルとHTTPアクセスされる実ファイルのマッピングが誤っていると、いくら待っても、preloadの表示のままになります。

 

http://localhost:8000/target.html

まとめ

 

仮想フォルダを準備するというのにちょっと躓きましたが、思ったより、やってみると簡単だった。人力検索はてなの質問者様、回答者様に感謝です。

 

以上、ファイルの読み込みのあるCやC++EmscriptenJavaScriptに変換する方法でした。

 

参考資料

関連記事

6年前の記事