このトピックでは、ページの読み込み時にEmscriptenの仮想ファイルシステムに格納されるファイルのパッケージ化について説明します。
ファイルのパッケージ化には、*プリロード*と*埋め込み*の2つの方法があります。埋め込みは、指定されたファイルをwasmファイル内に格納します。プリロードは、それらを別々のバンドルにパッケージ化します。別途ダウンロードしてコピーする必要がないため、ファイルを埋め込む方がプリロードよりも効率的ですが、プリロードはデータを個別にホストするオプションを有効にします。
emccは、ファイルパッケージャを使用してファイルをパッケージ化し、実行時にファイルシステムを作成してロードするファイルシステムAPI呼び出しを生成します。emccがパッケージ化に推奨されるツールですが、手動でファイルパッケージャを実行する方が理にかなう場合があります。
--use-preload-plugins
を使用すると、拡張子に基づいてファイルを自動的にデコードできます。詳細については、ファイルのプリロードを参照してください。
ファイルをパッケージ化する最も簡単な方法は、コンパイル時にemccを使用することです。preloadコマンドとembedコマンドは、それぞれ対応するパッケージ化方法を選択します。
以下のコマンドは、ファイルをプリロード用にパッケージ化する方法を示しています。
emcc file.cpp -o file.html --preload-file asset_dir
このコマンドは、**file.html**、**file.js**、**file.data**を生成します。**.data**ファイルには**asset_dir/**内のすべてのファイルが含まれており、**file.js**によってロードされます。
注記
チュートリアルでは、**hello_world_file.cpp**テストコードを使用してプリロードを実演しています。
埋め込みのコマンドを以下に示します。この場合、emccは**file.html**と**file.js**を生成します。**asset_dir/**の内容は**file.js**に直接埋め込まれます。
emcc file.cpp -o file.html --embed-file asset_dir
デフォルトでは、パッケージ化するファイルは、コンパイル時のコマンドプロンプトディレクトリ内またはその下にネストされている必要があります。実行時には、同じネストされたファイル構造が仮想ファイルシステムにマッピングされ、ルートはコマンドプロンプトディレクトリに対応します。
たとえば、プロジェクトが**dir2**からコンパイルされている**dir1/dir2/dir3/asset_dir/**というファイル構造があるとします。**asset_dir**をパッケージ化する場合、その相対的な場所**dir3/asset_dir/**を指定します。
emcc file.cpp -o file.html --preload-file dir3/asset_dir
このフォルダは、実行時の仮想ファイルシステムの同じ場所**dir3/asset_dir**で使用できます。同様に、dir2にファイルをパッケージ化すると、実行時の仮想ファイルシステムのルートで使用できます。
@
記号を使用して、ローカルファイルシステムの任意の場所から仮想ファイルシステムの任意の場所にパッケージ化されたファイルをマッピングできます。これについては、以下で仮想ファイルシステムでのファイルの場所の変更で説明します。
file_packagerの先頭にある手順を使用して、ファイルパッケージャを手動で実行することもできます。
ファイルパッケージャは**.data**ファイルと**.js**ファイルを生成します。**.js**ファイルにはデータファイルを使用するためのコードが含まれており、メインのコンパイル済みコードをロードする*前*にロードする必要があります。(たとえば、<script>
タグを--shell-file
の最後に、{{{ SCRIPT }}}`
の直前に追加します。)
注記
ファイルパッケージャを使用すると、コードのコンパイルとは別にファイルのパッケージ化を実行できます。
各ファイルに対してファイルパッケージャを実行し、**.js**出力をロードすることにより、複数のデータファイルをロードできます。動的ロードの例についてはBananaBread(cube2/js/game-setup.js)を参照してください。
デフォルトでは、プリロードされたすべてのファイルを含む**.data**ファイルは、**.js**ファイルと同じURLからロードされます。場合によっては、他のファイルとは異なる場所にデータファイルがある方が便利な場合があります。たとえば、**.html**と**.js**が頻繁に変更される場合、データファイルを別の高速なCDNに保持したい場合があります。
このモデルは、Module.locateFile
関数を指定して、データファイルが格納されているURLを返すようにすることでサポートされます。この関数は、データファイルをロードする<script>
要素の前に指定する必要があります。
パッケージ化のデフォルトのアプローチは、コンパイル時のネストされたファイル構造(コンパイル時のコマンドプロンプトディレクトリを基準とする)を仮想ファイルシステムのルートに直接マッピングすることです。@
記号は、ビルド時のパスで使用して、実行時の仮想ファイルシステム内のリソースの場所を*明示的に*指定できます。
注記
@
記号が必要となるのは、コンパイル時ディレクトリの下にネストされていない、したがって仮想ファイルシステム内の場所へのデフォルトのマッピングがないファイルをパッケージ化する場合に役立つことがあるためです。
たとえば、プリロードされたフォルダ**../../asset_dir**を仮想ファイルシステムのルート(**/**)にマッピングするには、次のようにします。
emcc file.cpp -o file.html --preload-file ../../asset_dir@/
新しいパスとファイル名にマッピングすることもできます。たとえば、埋め込みファイル**../res/gen123.png**を**/main.png**として使用できるようにするには、次のようにします。
emcc file.cpp -o file.html --embed-file ../res/gen123.png@main.png
ファイル名には、A-Z
、a-z
、0-9
、スペース文字、および!#$%&'()+,-.;=@[]^_`{}~
のいずれかの文字を使用できます。さらに、ホストファイルシステムがサポートしている場合は、"*<>?|
を使用できます(Windowsでは、ファイル名にこれらを使用できません)。コマンドラインで@
文字を指定する場合は、src@dst
マッピング表記(上記参照)をトリガーしないように@@
という形式でエスケープする必要があります。/
、\
、:
の文字は使用できません。
重要
ダウンロードサイズを削減し、起動速度を向上させるために、アプリが実際に必要とするファイルのみをパッケージ化してください。
実行時に実際に使用されるファイルをログに記録するオプションがあります。これを使用するには、Module.logReadFiles
オブジェクトを定義します。読み取られたファイルごとに、stderrにログが記録されます。
別の方法としては、コンパイル済みのJavaScriptでFS.readFiles()
を確認します。これは、読み取られたすべてのファイルのキーを持つオブジェクトです。ログよりも使用しやすい場合があり、潜在的に複数のファイルアクセスではなく、ファイルが記録されます。
注記
FS.readFiles()
オブジェクトを変更したり、完全に削除したりすることもできます。これは、たとえば、アプリ内の2つの時点間でどのファイルが読み取られたかを確認する場合に役立ちます。
--use-preload-plugins
オプションを使用すると、ファイルの拡張子に基づいて自動的にデコードできます。 これは、各ファイルに対してemscripten_run_preload_plugins()
を手動で呼び出すことによっても実行できます。 ファイルはファイルシステムに元の形式で保存されたままですが、デコードされた形式を直接使用できます。
サポートされている形式は以下のとおりです。
画像 (.jpg
、.jpeg
、.png
、.bmp
): ブラウザの画像デコーダを使用してファイルがデコードされ、IMG_Load
(emscripten_get_preloaded_image_data()
に依存するSDL1およびSDL2ポート)で使用できます。(無効にするには、Module.noImageDecoding
を true
に設定します。)
オーディオ (.ogg
、.wav
、.mp3
): ブラウザのオーディオデコーダを使用してファイルがデコードされ、Mix_LoadWAV
(SDL1のみ)で使用できます。(無効にするには、Module.noAudioDecoding
を true
に設定します。)
動的ライブラリ (.so
): ファイルは事前にコンパイルされ、WebAssembly.instantiate
を使用してインスタンス化されます。 これは、大きなWebAssemblyモジュールの非同期コンパイルが必要なChromeなどのブラウザで役立ちます。その後、後でdlopen
を使用してモジュールを同期的にロードできます。(無効にするには、Module.noWasmDecoding
を true
に設定します。)
テストスイートには、多くのファイルパッケージングの例が含まれており、動作するコードを検索するのに最適な場所です。