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

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

React なプロジェクトを TypeScript に移行したら3つの困りが発生したけど解決できたメモ

こまったこと:

1. カスタムソースディレクトリー ./src.reacttsc が認識できなかった

諸事情により ./src ではなく ./src.react に react 用のソースを配置していたが、 tsconfig.jsoninclude では "." 文字の入ったディレクトリーは認識しない仕様らしく困りました。

考えた解決方法:

  1. symlink を作って渡す
  2. ./src-react に変える

もんやり感はありましたが (2) でディレクトリーの名前から "." を排除して解決しました。ちなみに React のソースファイルパスのカスタムは react-app-rewired で eject-free に対応しています。

2. .tsx 化したモジュールで他の .tsx 化したモジュールを import できなかった

  • import Hoge from "./Hoge.tsx" ← ダメ🙅‍♀️
  • import Hoge from "./Hoge" ← ヨシ!🙆‍♀️

3. 独自定義のタグが JSX.IntrinsicElements に無いですよエラーで困った

独自定義のタグ、例えば GUI のルック・アンド・フィール的に Xel を使っていると <x-box> とか <x-button> とか使います。TypeScript化していない状態では一般的なHTMLタグと同様に埋め込めましたが、 TypeScript にしたら

Property 'x-box' does not exist on type 'JSX.IntrinsicElements'. TS2339

などと怒られてビルドできなくなりました。

単純なタグとしてのみの場合、かつ独自定義のタグが少ない場合は、

declare global
{ namespace JSX
 { interface IntrinsicElements
  { "my-awesome-tag": React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>; 
  }
 }
}

↑のようにまじめに TypeScript らしさを残したハック的なコードを <my-awesome-tag> を使いたい .tsx ファイル冒頭へ加えればよい。よいのだけど、 Xel を使いたい場合のようにたくさんのタグをぶちこみたい場合や、独自定義のタグに独自定義のプロパティーも使いたい場合は、 TypeScript にこだわって疲弊するよりは↓型は any にして "my-awesome-tag": any; のようにすると少し楽です。

参考

Web 向けの3D の GPU 描画コンテキストお取り扱いライブラリーの2020-07時点のメモ: ES 系, Unity, Unreal Engine, Rust 系

note: 2D 系(eg. phaser, ggez, etc. )は今回のメモでは含めていません。

Lang Library License WebGPU WebGL native ES & wasm
ES babylon.js Apache-2.0 Ready 2 %a n/a pure ES
ES three.js (+A-Frame) MIT(+MIT) (unknown†1) 1 + (2) n/a pure ES
ES playcanvas MIT (unknown†2) 2 %b n/a pure ES
C++ Unreal Engine *1 (unknown) 1 %c D3D12, Metal, OpenGL wasm(Emscripten)
C# Unity *2 (unknown) 2 %d D3D12, Metal, OpenGL wasm(Emscripten)
Rust unrust Apache-2.0 (unknown) 2 OpenGL wasm
Rust Amethyst(≈rendygfx-hal) Apache-2.0 or MIT (unknown; potentially maybe) (2;potentially) Vulkan, Metal, OpenGL wasm(; experimental)
Rust harmony Zlib (unknown†4; potentially yes) (2;potentially) Vulkan, Metal wasm(; help wanted)
Rust oxidator MIT (potentially yes) n/a Vulkan, D3D12 wasm(; not yet)
Rust piston MIT (unknown) n/a n/a n/a

おまけ: 所感

  • pure-ES 系で特に WebGPU を見据える場合は babylon.js で書くのが良さそう
  • リッチなエンジン系は…
    • Unreal EngineHTML5 出力は現実的に考えない方がいいです(UE5移行へWebGPUと併せて期待したいけど、期待しないでおいた方がいいかも)
    • 豊富なエコシステムやコミュニティーもあるので Unity で WebGL2 バックエンドにするのが現時点だけを見るなら現実的で良いかもしれません
    • Web 親和性の点では playcanvas もよいかもしれません
  • Rust 系は...
    • unrust は現時点で Web へきっちり出力できるたぶん唯一の3D-GPU描画系です
    • Amethyst は wasm+GL サポートを開発途中ですが、このメモの作成時点では全ての要素技術にかなり強い技師でも辛うじてバギーながらChromeで動くような動かないような微妙な出力に辿り着ける程度の状態です
    • harmony は描画バックエンドのポテンシャル的には WebGPU 対応、 OpenGL 対応により Web 出力できますが、採用する ECS バックエンドやマルチスレッドに最適化しまくっている事から WebWorker の制限と性能の懸念などもあり今の所 Author は Web 出力にそれほど積極的ではないようです。(Webよりエンジンとしての機能実装を進めたい状況でもあります)
    • oxidatorRTS ゲームエンジンに特化していますが、 Author も WebGPU での Web 出力は視野にあるようです。いまのところは WebGPU や rust と wasm 処理系の進化、ウェブブラウザーの進化待ちのようです
    • piston は Web に興味無さそうです

少なくとも、 Web 向けアプリの 3D-GPU 描画系に現時点で Rust を採用するのはわりとしんどいです。3年後に WebGPU と Rust/wasm 処理系が最高の選択肢になっている可能性はわりと高いとは思いますが、いまはまだしんどいです。 Rust を採用したい場合も、恐らく 3D-GPU 描画系はうまく機能分離し、できるだけ疎結合に近い設計にしつつ、ビジネスロジック部分は Rust で書いて wasm-unknown-unknown ターゲットで wasm を wasm-bindgen で library としてフロントエンドから叩く感じで作っておき、フロントエンドとして GUI系、 3D-GPU 描画系は pure-Web 系またはそれに近い要素技術でカバーするのが現時点では合理的かもしれません。

例えばフロントエンドは React あるいは yew と HTML と ES のライブラリーで GUI を作り、 3D-GPU 描画系は babylon.jsbabylon.rs で取り込み、アプリ本体の処理、状態やリソースの管理、Entity-Component-System、などなどは pure-Rust または wasm 対応が面倒ではない範囲の Rust のエコシステムを用いて作り、 wasm-bindgen で .wasm に固めるとか。

Arch Linux 環境で cargo が言うことを聞かなくなったメモ

症状

  • 数日ぶり程度に使用した Arch Linux 環境の rust 処理系で
  • cargo+nightly を受け付けてくれなくなって困った ( -Z したかった )
  • rustup toolchain では stable, nightly が installed 状態

原因

  • rust は rustup を per user で導入して使っていた"はず"だったのに
  • /sbin/cargo が実行されていた ( which cargo で判明 )
  • /sbin/cargo は stable

なぜ /sbin/cargo が環境に "いつのまにか" install されてしまったのか考えると、この数日の間に実験的に yay で rust 製のツールをシステムへ install した事を思い出しました。 yay での install ではビルドツールチェインも芋蔓し、途中の選択肢によってはビルドツールチェインはビルド後に remove できたりするのですが、おそらく yay で rust 製のツールをシステム導入した際にビルドツールチェインの remove を選択ミスしたためシステムパッケージ版の rust が導入された状態になってしまい、意図しない cargo = /sbin/cargo~/.cargo/bin/cargo よりパスが優先される状態に陥っていたのだろうと思います。

解決

  • yay または pacman で rust パッケージを削除 ( per user で導入している rustup には影響しません )

おまけ: Arch Linux ゆえ

同様の症状の状態は Ubuntu など他の GNU/Linux 環境でも発生させる事はできますが、 AUR と yay のようにユーザーの環境でソースコードからビルドするタイプのパッケージ管理システムを常用していない限り、"意図せず"に発症する事は無いと思います。Gentoo で emerge している場合は似た状況がうっかり発生する事もあるのかも。

MDN の wasm-bindgen の入門用チュートリアル "Hello, WebAssembly" の補足的なメモ

"Hello, WebAssembly"

補足的なメモ

1. npm のアカウントとパッケージの公開は必要?

MDNの記事そのものではそこも含めたやり方の例として必要としていますが、本質的には不要です。 npm へ @mynpmusername/hello-wasm パッケージを公開せずにこのチュートリアルを進める場合は:

  1. 「パッケージの npm への発行」の直前までは記事の通り進めます
  2. package.jsondependencies.@mynpmusername/hello-wasm をバージョン番号表記ではなく "file:./hello-wasm/pkg" のようにローカルファイルシステムからのパッケージ参照で記述します
  3. npm install または yarn すると他の依存パッケージ群と併せて @mynpmusername/hello-wasm./hello-wasm/pkg から node_modules へ install されます
  4. 続きは記事の通り進めます

2. webpack 使う必要ある?

Webサービスとしてデプロイする形態で動作確認してみたければ事実上必要です。

webpack-dev-serverすると index.js, node_modules の中身(hello-wasm/pkgからnode_modulesへinstallされた@mynpmusername/hello-wasmパッケージも含みます)を統合して開発用のhttpdwebpack.config.jsの定義に従って起動してくれます。webpackを使わないとnode_modulesのパッケージ群が統合されないため一般的なhttpdで単純にディレクトリーを指定して起動しても期待動作しません。

hello-wasm を直接 Node.js のインタラクティブ・シェルで叩いて確認したいだけなら不要です。 WebAssemblyコードのロードと実行 - WebAssembly | MDNfetch を Node.js の require('fs').readFileSync などに置き換えて .wasm ファイルをロードして WebAssembly.instantiate を叩けば .wasm のより原始的な動作確認も可能です。

3. 一般的なhttpdへデプロイしたい場合はどうするの?

npm run webpack または yarn webpack などすると webpack-cli パッケージの webpack コマンドにより ./dist へ一般的なhttpdへデプロイできるファイル群が生成されます。./dist に生成された中身とindex.htmlを同じディレクトリーで参照可能な配置を行い、httpd でホストすると期待動作します。たぶん。

例えばChromeで期待動作せず Console に↓のエラーが出ている場合はホストしている httpd が .wasm の MIME を正しく application/wasm で出力できていません。たぶん。うまいこと MIME を吐くように設定して下さい。

localhost/:1 Uncaught (in promise) TypeError: Failed to execute 'compile' on 'WebAssembly': Incorrect response MIME type. Expected 'application/wasm'.

4. npm より yarn

どうぞお好きな方で大丈夫です。

WebGPU 実装状況のメモ; Firefox-80.0a1(nightly), Chrome-86.0.4191.0(canary) なう

  • [OK🙆‍♀️] Firefox-80.0a1(nightly) + gfx.webrender.all=True + dom.webgpu.enabled=True / Windows 10
  • [NG🙅‍♀️] Firefox-78.0.1(stable) + gfx.webrender.all=True + dom.webgpu.enabled=True / Windows 10
  • [OK🙆‍♀️] Chrome-86.0.4191.0(canary) + Unsafe WebGPU=Enabled / Windows 10
  • [NG🙅‍♀️] Chrome-83.0.4103.116(stable) + Unsafe WebGPU=Enabled / Windows 10

note: Firefox のフラグは about:config, Chrome のフラグは chrome:flags から設定。ほかに Safari / macOS or iOS でも試せるらしいけどうちには環境無いので確認していません。Android, Chrome OS, GNU/Linux では Chromium, Firefox の WebGPU サポートはまだ進んでいないみたいです。実装状況の概況 -> https://github.com/gpuweb/gpuweb/wiki/Implementation-Status

動作確認は https://austineng.github.io/webgpu-samples/ より。参考 -> https://hacks.mozilla.org/2020/04/experimental-webgpu-in-firefox/

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

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

CRA=create-react-app が WSL で start できない理由と回避方法のメモ

問題

WSLでCRAしてyarn startするとcmd.exeを実行できずにウェブブラウザーの起動どころかサーバーも起動せず死んでしまいます。

再現方法:

  1. WSLで
  2. npx create-react-app hoge して
  3. cd hoge; yarn start します
Starting the development server...

events.js:291
      throw er; // Unhandled 'error' event
      ^

Error: spawn cmd.exe ENOENT
    at Process.ChildProcess._handle.onexit (internal/child_process.js:268:19)
    at onErrorNT (internal/child_process.js:468:16)
    at processTicksAndRejections (internal/process/task_queues.js:80:21)
Emitted 'error' event on ChildProcess instance at:
    at Process.ChildProcess._handle.onexit (internal/child_process.js:274:12)
    at onErrorNT (internal/child_process.js:468:16)
    at processTicksAndRejections (internal/process/task_queues.js:80:21) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'spawn cmd.exe',
  path: 'cmd.exe',
  spawnargs: [ '/s', '/c', 'start', '""', '/b', 'http://localhost:3000' ]
}
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

そもそもWSLで実行しているのにcmd.exeなどとわけのわからない事を言われたので「またyarnか何かの実行バイナリーがWSL内ではなくWindowsの何かが何故か優先されているふぁっきゅーかな」と思いましたが、同じくらいふぁっきゅーなCRA側の問題でした。

回避策; 本質的な解決策は執筆時点でもまだCRAにマージされていません

1. BROWSER=none 戦術

いまのところ、わたしのおすすめはこちらの回避策です。

  • yarn startBROWSER=none yarn start にします
  • または package.json"start": "BROWSER=none react-scripts start" して yarn start します

note:

  • package.json を変更する場合に、開発環境の可搬性に PowerShell, cmd など対応したい場合は cross-env 付きで仕込みます。
    • またはプロジェクトで採用するビルドエコシステムの方針によって run-script-os が有用な場合もあるかもしれません。
 "scripts": {
  "start": "run-script-os",
  "start:default": "cross-env BROWSER=none react-scripts start",
  "start:win32": "react-scripts start",

2. PATH=$PATH:/mnt/c/Windows/System32 戦術

  • yarn startPATH=$PATH:/mnt/c/Windows/System32 yarn start にします
  • または package.json"start": "PATH=$PATH:/mnt/c/Windows/System32 react-scripts start" して yarn start します
  • または WSL の実行環境の PATHexport PATH=$PATH:/mnt/c/Windows/System32 します
  • または /etc/wsl.conf[Interop] セクションで appendWindowsPath = True または False を定義しない設定へ変更します
  • または cmd.exe を実行可能な他のお膳立てをしてあげます

原因

  • CRAがブラウザーを起動するために"cmd.exeを使える状態を前提"にのみ実装されている
  • is-wsl で WSL を検出して気を利かせてcmd.exeを起動しようとしているっぽい †参考1

参考

関連おまけ

思うところメモ

BROWSER=none 回避策は PATH 回避策より一般的には良いです。WSLのユーザーのおそらくほとんどはWSLを"WindowsGNU/Linux悪魔合体した何か"ではなく、Windowsから便利に利用しやすいGNU/Linux環境として利用し、WSLがWindows上で実行されながらもWindows特有の環境要因にはできるだけ依存せずGNU/Linux環境としての純粋性や可搬性を維持したWindowsとは異なる環境かつWindowsとのつながりもユーザーが求めれば構築しやすい、そんな何かであることを望んでいるのではないかな、と思います。参考の Issue #7251 でもそういう考え方の開発者さんは少なくも無さそうな雰囲気があります。

もちろん、is-wslからcmd.exeによるWindowsネイティブのブラウザー呼び出しを試みようとする、その気の利いた工夫は良い事です。しかし、現状の実装は想定が甘く、WSLを悪魔合体的な環境で利用されている状況だけを前提に fallback も無い実装になっている事が悲しみを生んでしまった原因になっていると思います。開発環境の可搬性も保守性には有用な視点の1つにもなりますし、 default でも巧く解決されて多くのユーザーが意図に反したエラーに悩まされない実装になると嬉しいです。

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)を再開できます。もっとスタイリッシュでコスト的な合理性も高い解決方法に気付いた際にはぜひ教えて下さい。

参考

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