C++ ときどき ごはん、わりとてぃーぶれいく☆

USAGI.NETWORKのなかのひとのブログ。主にC++。

UE-4.23以降でHTML5ターゲット(wasm+webgl1)をWindowsの開発機から使うメモ; UE-4.24, Emscripten-1.39.0

f:id:USAGI-WRP:20200703162337p:plain

↑一応、できました。ただし、実用上は UE4.23 以降で HTML5 ターゲットの採用はおすすめしません。…UE5時代にはWebGPU/wasmのポータブルターゲットよゆうでしたの世界が来ると楽しいですね…

理由:

  1. エンジンソースレベルからのビルド、Emscriptenによるサードパーティーライブラリーのビルドが必要 // 半日から1日程度の作業時間が必要になります。Windowsでやると怪奇現象に消耗します
  2. UE4HTML5ターゲットはWebGL1≈OpenGL ES2 なので何かとしんどい // 執筆時点で既に世の中は WebGL2 どころか WebGPU 普及が始まる頃合いです
  3. エンジンほか準備できた後も、UE4のユーザープロジェクト規模の Emscripten での翻訳はすごーく時間がかかります // 目安としては通常の C++ native の数倍程度でしょうか…TPSテンプレ初期状態でも30分くらい掛かります
  4. どうしてもUEでHTML5ターゲットを使いたければUE<=4.22を使えばいいと思います // 本体にHTML5ターゲットが内蔵されている最終版です

つらくても UE4.23 以降で HTML5 ターゲットをどうしても使いたい場合のメモ

note:

  • すべて Git-Bash 処理系でコマンドします。手順(1,2,4)は PowerShell でも処理できますが、
    • 手順(3)は Windows 開発機の場合は Git-Bash 処理系を前提に作られています。
    • 仮に WSL2 でコマンドしても手順(3)自体は完了できますが、 EmscriptenGNU/Linux 向けの構成になりやり直しになるかもしれません。
  • このメモの時点で既に UE-4.25.1 がリリース済みですが、 HTML5 プラットフォーム用のリポジトリーは 4.24 向けが現行最新のままです。
    • そうではなくなる未来もあるかもしれません。
  • 以下の手順の通りでやると手順(4)へ進んでから爆発する可能性があるので、先に "†追記5" を確認した方がよいかもしれません。
    • 開発環境は GNU/Linux がいいと思います // Windows + git-bash だと何かと面倒や謎のエラーに見舞われてリソースを浪費します

手順

  1. ssh:git clone -b 4.24-html5 --single-branch git@github.com:UnrealEngineHTML5/UnrealEngine.git ue4-r424-html5
    • or https:git clone -b 4.24-html5 --single-branch https://github.com/UnrealEngineHTML5/UnrealEngine ue4-r424-html5
    • UEリポジトリーを複製
    • 主に回線の太さ次第ですが数分程度で完了します
  2. cd ue4-r424-html5; ./Setup.bat
    • .netやDirectXなど依存フレームワークとランタイムライブリーを自動的に導入します
    • 回線の太さや導入の処理速度によりますが数分から十数分程度で完了します
  3. cd Engine/Platforms/HTML5; ./HTML5Setup.sh
    • Emscripten開発環境を自動的に構築し、UEのHTML5プラットフォームに必要なあれこれも自動的にビルドします
    • 主にPCの処理性能次第ですが数時間程度掛かります
    • †追記1
  4. cd ../../../; ./GenerateProjectFiles.bat
    • Windows用のUEのビルドプロジェクトを生成します
    • .bat版はVisual Studio(=Windows)を前提とした構成を行います
    • .sh版はDarwin(=macos)かそれ以外(=GNU/Linux)用で、それぞれ専用のLLDB系またはGDB系を用いた構成を行います
    • †追記2,†追記3
  5. プロジェクトのルートに生成されている UE4.sln を VS2019 で開いてビルドします
    1. 共通設定
      • Platform -> Win64
      • Configuration -> Development Editor
    2. Program の一部をビルド
      1. Program に HTML5LaunchHelper ( Engine/Platforms/HTML5/Source/Programs/HTML5/HTML5LaunchHelper/HTML5LaunchHelper.csproj ) を追加
      2. { AutomationTool, AutomationToolLauncher, UnrealBuildTool, HTML5LaunchHelper, ShaderCompileWorker, UnrealLightmass, UnrealPak, UnrealFileServer, UnrealFrontend } をビルド
        • CTRL+CLICKなどで複数選択、CTRL+B (Build Selection) などで選択プロジェクト群をビルド
        • 主にPCの処理性能次第ですが数十分程度掛かります
    3. Engine の UE4 をビルド
      • †追記4
  6. ./Engine/Binaries/Win64/UE4Editor.exe -log
    • このパスはプロジェクトルートからの相対パスの場合です
    • -log はログを標準出力へ出すオプションです。付けなくても UE4Editor 自体は起動します。たぶん
    • 主にPCの処理性能次第ですが初回起動は十数分程度かかります。 Unreal Project Browser が出現し操作可能になれば起動成功です
  7. Unreal Project Browser から適当なUEプロジェクトを作り HTML5 出力を試す
    1. プロジェクト作成
      1. Games -> Next
      2. Third Person -> Next; なんでもよい
      3. With Starter Content を No Starter Content に変更; 不要なので
      4. Folder, Name を適当に設定 -> Create Project
    2. プロジェクトの設定
      • Platforms / HTML5: Packaging / Compress files during shipping packaging を ON
      • Project / Packaging: Packaging / Use Pak File を OFF
    3. Launch / Packaging
      • Project Launcher から HTML5/Chrome, HTML5/Firefox 何れかで Launch すれ…ば…動く…ハズぅ…
      • †追記5
      • 主にPCの処理性能次第ですがブラウザーが起動するまでに数十分程度掛かります
      • FirefoxLinkError: shared memory is disabled が出た場合は about:config -> javascript.options.shared_memory を true に切り替えてリロード…永遠に始まらない…(ごめんもう諦めた
      • Chrome では動きました (冒頭のスクリーンショット)
      • Project Launcher だとログ用のファイルか何かがロックされて実行に失敗する怪奇現象も起きたので、とりあえず的には Packaging して出力先にできる HTML5LaunchHelper.exe を実行または適当な httpd を動かして動作確認するのが良さそうです

すごい無駄につかれてしまいました。

†追記1

↓が出たら:

./emsdk: line 18: /c/Users/usagi/AppData/Local/Microsoft/WindowsApps/python3: Permission denied

自分で入れたはずの Python3 ではなく↑のパスが出ている場合は Windows 設定の manage app execution aliases で "App Installer" (アプリ インストーラー) の python3.exeOff にします。手順(3)のコマンドは成功する前提で処理が書かれているので、一度↑で失敗した場合は rm -rf ./Build/emsdk/emsdk-1.39.0 して HTML5Setup.sh の内部フラグを Emscripten の導入が行われるよう細工するか、手コマンドで ./Build/emsdk/emsdk-1.39.0/emsdk install 1.39.0 し clone 済みの emsdk に 1.39.0 を手導入させてから ./HTML5Setup.sh を再実行して Emscripten の導入以降の処理を行わせます。

"以降の処理"は具体的にはサードパーティーライブラリー群のEmscriptenによるビルドと完了通知の表示と音の再生がコードされています。このサードパーティーライブラリー群のビルドが非常に長い時間を要します。ビルドされるライブラリーは:

  • zlib
  • libPNG
  • Ogg
  • Vorbis
  • libOpus
  • ICU
  • HarfBuzz
  • FreeType2
  • PhysX3

です。これらのビルドは ./HTML5Setup.sh 経由で呼ばれる ./Build/BatchFiles/Build_All_HTML5_libs.sh にコードされています。1つ1つシーケンシャルにビルドする実装になっていますが、それぞれのビルドごとコンパイルはCPUを使えるだけ並行に行われます。

†追記2

以下のようなエラーが表示されるかもしれません:

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targe
ts(1177,5): error MSB3644: The reference assemblies for .NETFramework,Version=v4.6.2 were not found. To resolve this, i
nstall the Developer Pack (SDK/Targeting Pack) for this framework version or retarget your application. You can downloa
d .NET Framework Developer Packs at https://aka.ms/msbuild/developerpacks [C:\Users\usagi\tmp\ue4-r424-html5\Engine\Sou
rce\Programs\UnrealBuildTool\UnrealBuildTool.csproj]

"VS2019の.net framework 4.6.2"開発環境が無い場合は https://aka.ms/msbuild/developerpacks から "Developer Pack" を入れます。"Runtime"ではなく"Developer Pack"です。

†追記3

emsdk内のnodeが NOT FOUND なエラーが表示されるかもしれません:

ERROR: NODEJS NOT FOUND: C:\Users\usagi\tmp\ue4-r424-html5\Engine\Platforms\HTML5\Build\emsdk\emsdk-1.39.0\node\12.9.1_64bit\bin\node.exe

プロジェクトルートのGenerateProjectFiles.batから内部的に呼ばれる./Engine/Build/BatchFiles/GenerateProjectFiles.batからさらに内部的に呼ばれる./Engine/Binaries/DotNET/UnrealBuildTool.exeが翻訳時に埋め込んでいるemsdk内部のnodejsのバージョンが実際にユーザーがemsdkでEmscriptenを導入した時点で取り扱いのあるnodejsのバージョンと異なる場合に発生します。

UnrealBuildTool.exeのnodejsのバージョンの埋め込みをコードしたソースファイルは./Engine/Platforms/HTML5/Source/Programs/UnrealBuildTool/HTML5SDKInfo.csで:

     static string NODE_VER = "12.9.1_64bit";

     static string NODE_VER = "12.18.1_64bit";

のように実際に emsdk で導入されている nodejs のバージョンに書き換えます。導入状況に応じた正しい nodejs のバージョンは emsdk 内の nodejs ディレクトリーを見るか、 ./Engine/Platforms/HTML5/emsdk/emsdk-1.39.0/emsdk list して確認するとわかります。

HTML5SDKInfo.csを書き換えたら手順(4)のコマンドを再実行します。

なお、手順(4)でこのようなエラーが表示されても処理が中断される事はありませんが、事実上失敗なのでエラーが発生せずに完了できるようになるまでどうにかします。

†追記4

c1xx : error C3859: Failed to create virtual memory for PCH
  c1xx: note: the system returned code 1455: The paging file is too small for this operation to complete.

↑C3859が大量に出る場合は、 Windows の Control Panel -> System and Security -> System -> System Properties / Advanced / Performance : Settings... -> Performance Options / Advanced / Virtual memory : Change... でページングファイルが手動設定または小さく設定されていないか確認します。RAM=32GBの環境では自動設定にしておけばCPU=32coresでも数回発生する程度になります。その程度であればビルドを2回、3回程度実行すれば完了できるのでエンジンのビルドを頻繁に行うわけでなければ手ビルド数回する妥協策が合理的かもしれません。

C3859のかわりにC1076が大量にでるかもしれません。何れにせよMSVC++がメモリー使用について不器用なために発生します。もしかしたら /Zm を適当に設定すれば常に1回でビルドが完了できるようになるかもしれません。

†追記5

もう大丈夫、さあ、HTML5で動くのだ!!と思いましたが Launch してみると不穏な WARNING が Launching UAT... タスク中に発生し、その後のタスクが失敗していました:

WARNING: Library 'C:\Users\usagi\tmp\ue4-r424-html5\Engine\Platforms\HTML5\Source\ThirdParty\ICU\icu4c-64_1\lib-1.39.0-fc-mt\libicu_O2.bc' was not resolvable to a file when used in Module 'ICU', assuming it is a filename and will search library paths for it. This is slow and dependency checking will not work for it. Please update reference to be fully qualified alternatively use PublicSystemLibraryPaths if you do intended to use this slow path to suppress this warning.
WARNING: Library 'C:\Users\usagi\tmp\ue4-r424-html5\Engine\Platforms\HTML5\Source\ThirdParty\PhysX3\PhysX_3.4\lib-1.39.0-fc-mt\PhysX3_O2.bc' was not resolvable to a file when used in Module 'PhysX', assuming it is a filename and will search library paths for it. This is slow and dependency checking will not work for it. Please update reference to be fully qualified alternatively use PublicSystemLibraryPaths if you do intended to use this slow path to suppress this warning.
WARNING: Library 'C:\Users\usagi\tmp\ue4-r424-html5\Engine\Platforms\HTML5\Source\ThirdParty\PhysX3\PhysX_3.4\lib-1.39.0-fc-mt\PhysX3Common_O2.bc' was not resolvable to a file when used in Module 'PhysX', assuming it is a filename and will search library paths for it. This is slow and dependency checking will not work for it. Please update reference to be fully qualified alternatively use PublicSystemLibraryPaths if you do intended to use this slow path to suppress this warning.
WARNING: Library 'C:\Users\usagi\tmp\ue4-r424-html5\Engine\Platforms\HTML5\Source\ThirdParty\PhysX3\PhysX_3.4\lib-1.39.0-fc-mt\PhysX3Cooking_O2.bc' was not resolvable to a file when used in Module 'PhysXCookingLib', assuming it is a filename and will search library paths for it. This is slow and dependency checking will not work for it. Please update reference to be fully qualified alternatively use PublicSystemLibraryPaths if you do intended to use this slow path to suppress this warning.

これらは手順(3)で .bc が作成されているはずでした。 Success! って表示されていたし。しかし、実際にディレクトリーを確認してみると ICU は .bc が何も生成されていませんでした。 PhysX はたくさん .bc が生成されていましたが、↑ログでWARNINGされた *.bc 群は生成されていませんでした。偽サクセスだったよ、がっでむ。

なぜ生成されていないのか手順(3)のログのICUPhysXの *.bc 生成に注目して確認してみると:

--- Logging error ---
Traceback (most recent call last):
  File "D:\obj\windows-release\37amd64_Release\msi_python\zip_amd64\__init__.py", line 1029, in emit
  File "D:\obj\windows-release\37amd64_Release\msi_python\zip_amd64\__init__.py", line 1009, in flush
OSError: [Errno 28] No space left on device
Call stack:
  File "C:\Users\usagi\tmp\ue4-r424-html5\Engine\Platforms\HTML5\Build\emsdk\emsdk-1.39.0-fastcomp\fastcomp\emscripten\emcc.py", line 3715, in <module>
    sys.exit(run(sys.argv))
  File "C:\Users\usagi\tmp\ue4-r424-html5\Engine\Platforms\HTML5\Build\emsdk\emsdk-1.39.0-fastcomp\fastcomp\emscripten\emcc.py", line 2063, in run
    log_time('process inputs')
  File "C:\Users\usagi\tmp\ue4-r424-html5\Engine\Platforms\HTML5\Build\emsdk\emsdk-1.39.0-fastcomp\fastcomp\emscripten\emcc.py", line 218, in log_time
    logger.info('emcc step "%s" took %.2f seconds', name, now - TimeLogger.last)
  File "D:\obj\windows-release\37amd64_Release\msi_python\zip_amd64\__init__.py", line 1378, in info
  File "D:\obj\windows-release\37amd64_Release\msi_python\zip_amd64\__init__.py", line 1514, in _log
  File "D:\obj\windows-release\37amd64_Release\msi_python\zip_amd64\__init__.py", line 1524, in handle
  File "D:\obj\windows-release\37amd64_Release\msi_python\zip_amd64\__init__.py", line 1586, in callHandlers
  File "D:\obj\windows-release\37amd64_Release\msi_python\zip_amd64\__init__.py", line 894, in handle
  File "D:\obj\windows-release\37amd64_Release\msi_python\zip_amd64\__init__.py", line 1033, in emit

No space left on device だそうですが、Windowsもビルド環境も入っている唯一のドライブにはまだ150GB以上の余裕がありました。私はこの問題に正攻法で挑む気力と時間が勿体ないので、すぐに思いついたワークアラウンドを試しました:

  1. WSL2 で 手順(1),(2),(3)をGNU/Linux向けの手順で実行
  2. rsync -av ./Source/ThirdParty /mnt/c/Users/usagi/tmp/ue4-r424-html5/Engine/Platforms/HTML5/Source --include='*/' --include='*.bc' --exclude='*' --dry-run
  3. ↑から--dry-run を外して実行
    • WSL2 でビルドした *.bc ファイル群を Windows/git-bash で手順(7)まで進めていた作業ディレクトリーへ投げ入れています

Emscripten の WASM=1 で生成している *.bc は LLVM-bitcode なのでプラットフォーム可搬性があるので大丈夫です。たぶん。Windowsの複雑な開発環境で発生した謎の問題に対処するよりは私にとっては楽なワークアラウンドでした。

これで手順(7)を再開できます。もっとスタイリッシュでコスト的な合理性も高い解決方法に気付いた際にはぜひ教えて下さい。

参考

おおよそ↑のドキュメント群の通りコマンドをぽんぽん打ったら時間は掛かっても特に苦労は無いだろうと思ったのだけど😂