@next2d/builder 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +5 -1
  2. package/dist/index.js +140 -36
  3. package/package.json +3 -2
  4. package/templates/xbox/CMakeLists.txt +74 -2
  5. package/templates/xbox/README.md +73 -12
  6. package/templates/xbox/cmake/FetchDawn.cmake +47 -6
  7. package/templates/xbox/cmake/FindV8.cmake +22 -1
  8. package/templates/xbox/js/bootstrap.js +31 -28
  9. package/templates/xbox/js/selftest.js +740 -90
  10. package/templates/xbox/src/EventLoop.cpp +28 -1
  11. package/templates/xbox/src/EventLoop.h +12 -0
  12. package/templates/xbox/src/bindings/Audio.cpp +99 -15
  13. package/templates/xbox/src/bindings/Bindings.h +10 -0
  14. package/templates/xbox/src/bindings/Canvas.cpp +45 -0
  15. package/templates/xbox/src/bindings/Canvas2D.cpp +2 -5
  16. package/templates/xbox/src/bindings/DomShims.cpp +127 -0
  17. package/templates/xbox/src/bindings/EventTarget.cpp +2 -0
  18. package/templates/xbox/src/bindings/Fetch.cpp +2 -8
  19. package/templates/xbox/src/bindings/Image.cpp +212 -10
  20. package/templates/xbox/src/bindings/Polyfills.cpp +791 -0
  21. package/templates/xbox/src/bindings/Video.cpp +96 -7
  22. package/templates/xbox/src/bindings/webgpu/WebGPU.cpp +815 -15
  23. package/templates/xbox/src/bindings/webgpu/WebGPUCommon.h +3 -8
  24. package/templates/xbox/src/gpu/DawnContext.cpp +90 -3
  25. package/templates/xbox/src/gpu/DawnContext.h +18 -0
  26. package/templates/xbox/src/main.cpp +88 -6
  27. package/templates/xbox/src/platform/AudioEngine.cpp +9 -3
  28. package/templates/xbox/src/v8/V8Runtime.cpp +69 -4
  29. package/templates/xbox/src/v8/V8Util.h +29 -0
  30. package/templates/xbox/src/v8/WeakHandle.h +45 -0
  31. package/templates/xbox/src/worker/WorkerRuntime.cpp +325 -41
  32. package/templates/xbox/src/worker/WorkerRuntime.h +20 -10
  33. package/templates/xbox/tests/check_local.sh +3 -2
  34. package/templates/xbox/tests/raster_test.bin +0 -0
package/README.md CHANGED
@@ -48,9 +48,13 @@ On other platforms the builder scaffolds the host project and stages assets only
48
48
  See the generated `xbox/README.md` for full build steps.
49
49
 
50
50
  ```bat
51
- npx @next2d/builder --platform xbox --env prd --v8-root C:\path\to\v8
51
+ npx @next2d/builder --platform xbox --env prd
52
52
  ```
53
53
 
54
+ The prebuilt V8 engine is downloaded automatically on the first Xbox build
55
+ (published from the `build-v8` workflow). To use your own build, pass
56
+ `--v8-root C:\path\to\v8`.
57
+
54
58
  ### Scheduled introduction
55
59
 
56
60
  | platform |
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  "use strict";
3
3
  import pc from "picocolors";
4
4
  import fs from "fs";
5
+ import os from "os";
5
6
  import path from "path";
6
7
  import { fileURLToPath } from "url";
7
8
  import cp from "child_process";
@@ -76,8 +77,9 @@ const echoHelp = () => {
76
77
  console.log("For preview example:");
77
78
  console.log("npx @next2d/builder --preview --platform web --env prd");
78
79
  console.log();
79
- console.log("For Xbox build example (prebuilt V8 monolith path):");
80
- console.log("npx @next2d/builder --platform xbox --env prd --v8-root C:\\path\\to\\v8");
80
+ console.log("For Xbox build example (prebuilt V8 is downloaded automatically):");
81
+ console.log("npx @next2d/builder --platform xbox --env prd");
82
+ console.log("To use your own V8 build: --v8-root C:\\path\\to\\v8");
81
83
  console.log();
82
84
  process.exit(1);
83
85
  };
@@ -168,14 +170,14 @@ const loadConfig = async () => {
168
170
  */
169
171
  const buildWeb = () => {
170
172
  return new Promise((resolve, reject) => {
171
- const stream = cp.spawn("npx", [
173
+ const stream = $spawn("npx", [
172
174
  "@next2d/vite-plugin-next2d-auto-loader"
173
175
  ], { "stdio": "inherit" });
174
176
  stream.on("close", (code) => {
175
177
  if (code !== 0) {
176
178
  reject("vite plugin command failed.");
177
179
  }
178
- const stream = cp.spawn("npx", [
180
+ const stream = $spawn("npx", [
179
181
  "vite",
180
182
  "--outDir",
181
183
  $buildDir,
@@ -205,7 +207,7 @@ const installElectron = () => {
205
207
  if (fs.existsSync(`${process.cwd()}/electron/node_modules`)) {
206
208
  return resolve();
207
209
  }
208
- const stream = cp.spawn("npm", [
210
+ const stream = $spawn("npm", [
209
211
  "--prefix",
210
212
  `${process.cwd()}/electron`,
211
213
  "install",
@@ -281,7 +283,7 @@ const buildSteam = async () => {
281
283
  // copy HTML, JavaScript
282
284
  await copyResources();
283
285
  if (preview) {
284
- cp.spawn("npx", [
286
+ $spawn("npx", [
285
287
  "electron",
286
288
  `${process.cwd()}/electron/index.js`
287
289
  ], { "stdio": "inherit" });
@@ -339,7 +341,7 @@ const generateNativeProject = () => {
339
341
  if (fs.existsSync(`${process.cwd()}/${platform}`)) {
340
342
  return resolve();
341
343
  }
342
- const stream = cp.spawn("npx", [
344
+ const stream = $spawn("npx", [
343
345
  "cap",
344
346
  "add",
345
347
  platform
@@ -371,7 +373,7 @@ const runNative = async () => {
371
373
  const config = JSON.parse(fs.readFileSync(`${process.cwd()}/${CAPACITOR_CONFIG_NAME}`, { "encoding": "utf8" }));
372
374
  config.webDir = `${$outDir}/${platformDir}/${environment}/`;
373
375
  fs.writeFileSync(`${process.cwd()}/${CAPACITOR_CONFIG_NAME}`, JSON.stringify(config, null, 2));
374
- cp.spawn("npx", [
376
+ $spawn("npx", [
375
377
  "cap",
376
378
  "run",
377
379
  platform
@@ -394,7 +396,7 @@ const openNative = async () => {
394
396
  const config = JSON.parse(fs.readFileSync(`${process.cwd()}/${CAPACITOR_CONFIG_NAME}`, { "encoding": "utf8" }));
395
397
  config.webDir = `${$outDir}/${platformDir}/${environment}/`;
396
398
  fs.writeFileSync(`${process.cwd()}/${CAPACITOR_CONFIG_NAME}`, JSON.stringify(config, null, 2));
397
- const stream = cp.spawn("npx", [
399
+ const stream = $spawn("npx", [
398
400
  "cap",
399
401
  "sync",
400
402
  platform
@@ -404,7 +406,7 @@ const openNative = async () => {
404
406
  console.log(pc.red(`Failed to sync ${platform} project.`));
405
407
  return;
406
408
  }
407
- cp.spawn("npx", [
409
+ $spawn("npx", [
408
410
  "cap",
409
411
  "open",
410
412
  platform
@@ -428,7 +430,7 @@ const buildNative = async () => {
428
430
  const config = JSON.parse(fs.readFileSync(`${process.cwd()}/${CAPACITOR_CONFIG_NAME}`, { "encoding": "utf8" }));
429
431
  config.webDir = `${$outDir}/${platformDir}/${environment}/`;
430
432
  fs.writeFileSync(`${process.cwd()}/${CAPACITOR_CONFIG_NAME}`, JSON.stringify(config, null, 2));
431
- const stream = cp.spawn("npx", [
433
+ const stream = $spawn("npx", [
432
434
  "cap",
433
435
  "sync",
434
436
  platform
@@ -438,7 +440,7 @@ const buildNative = async () => {
438
440
  console.log(pc.red(`Failed to sync ${platform} project.`));
439
441
  return;
440
442
  }
441
- cp.spawn("npx", [
443
+ $spawn("npx", [
442
444
  "cap",
443
445
  "build",
444
446
  platform
@@ -469,6 +471,50 @@ const getTemplateDir = (name) => {
469
471
  * @constant
470
472
  */
471
473
  const XBOX_CONFIG_NAME = "MicrosoftGame.config";
474
+ /**
475
+ * @description npx / npm を子プロセスとして起動する (クロスプラットフォーム)。
476
+ * Windows では npx/npm が .cmd (バッチファイル) のため、shell 経由で
477
+ * ないと起動できない (spawn ENOENT / Node の CVE-2024-27980 対応により
478
+ * .cmd の直接 spawn も不可)。スペースを含む引数は二重引用符で保護する。
479
+ * Spawn npx/npm cross-platform. On Windows they are .cmd batch files,
480
+ * which require a shell to spawn.
481
+ *
482
+ * @param {string} command
483
+ * @param {array} args
484
+ * @param {object} options
485
+ * @return {object}
486
+ * @method
487
+ * @public
488
+ */
489
+ const $spawn = (command, args, options = {}) => {
490
+ if (process.platform === "win32" && (command === "npx" || command === "npm")) {
491
+ const quoted = args.map((a) => /\s/.test(a) ? `"${a}"` : a);
492
+ return cp.spawn(command, quoted, { ...options, "shell": true });
493
+ }
494
+ return cp.spawn(command, args, options);
495
+ };
496
+ /**
497
+ * @description 自動ダウンロードする prebuilt V8 のバージョン。
498
+ * `.github/workflows/build-v8.yml` で発行した Releases のタグと、
499
+ * `xbox-host-ci.yml` の V8_TAG に一致させること。
500
+ * The prebuilt V8 version to auto-download. Must match the release tag
501
+ * published by `build-v8.yml` and V8_TAG in `xbox-host-ci.yml`.
502
+ *
503
+ * @type {string}
504
+ * @constant
505
+ */
506
+ const XBOX_V8_VERSION = "13.7.152.19";
507
+ /**
508
+ * @description prebuilt V8 のアセットリビジョン。同一 V8 バージョンでも
509
+ * gn フラグ変更 (例: r2 = WebAssembly + DrumBrake 有効化) で
510
+ * バイナリが変わる場合に上げ、Release タグとローカルキャッシュを分離する。
511
+ * Asset revision. Bump when gn flags change for the same V8 version
512
+ * (r2 = WebAssembly + DrumBrake enabled).
513
+ *
514
+ * @type {string}
515
+ * @constant
516
+ */
517
+ const XBOX_V8_REVISION = "r3";
472
518
  /**
473
519
  * @description ゲーム側の `xbox/` へスキャフォールドしないテンプレート内ファイル。
474
520
  * - MicrosoftGame.config : ゲーム固有設定 (injectGameConfig が注入)
@@ -580,6 +626,59 @@ const copyXboxResources = () => {
580
626
  }
581
627
  });
582
628
  };
629
+ /**
630
+ * @description Xbox ビルドに使う V8 のパスを解決する。優先順:
631
+ * 1. `--v8-root` 引数
632
+ * 2. 環境変数 `V8_ROOT`
633
+ * 3. キャッシュ済みの prebuilt (%LOCALAPPDATA%/next2d/v8/<version>)
634
+ * 4. GitHub Releases (build-v8.yml が発行) から自動ダウンロード
635
+ * 3・4 により、通常は何も指定せずに `--platform xbox` だけでビルドできる。
636
+ * Resolve the V8 path for the Xbox build. With the cached/auto-downloaded
637
+ * prebuilt, no flag or env var is required in the common case.
638
+ *
639
+ * @return {Promise<string>}
640
+ * @method
641
+ * @public
642
+ */
643
+ const resolveXboxV8Root = async () => {
644
+ // 1. --v8-root 引数
645
+ if (v8Root) {
646
+ return path.resolve(process.cwd(), v8Root);
647
+ }
648
+ // 2. 環境変数 V8_ROOT
649
+ if (process.env.V8_ROOT) {
650
+ return process.env.V8_ROOT;
651
+ }
652
+ // 3. キャッシュ済み prebuilt
653
+ const cacheBase = process.env.LOCALAPPDATA
654
+ ? `${process.env.LOCALAPPDATA}/next2d`
655
+ : `${os.homedir()}/.cache/next2d`;
656
+ const cacheDir = `${cacheBase}/v8/${XBOX_V8_VERSION}-${XBOX_V8_REVISION}`;
657
+ if (fs.existsSync(`${cacheDir}/include/v8.h`)) {
658
+ return cacheDir;
659
+ }
660
+ // 4. GitHub Releases から自動ダウンロード (マシンごとに初回のみ)
661
+ const assetName = `v8-monolith-${XBOX_V8_VERSION}-windows-x64.zip`;
662
+ const url = `https://github.com/Next2D/builder/releases/download/v8-${XBOX_V8_VERSION}-windows-x64-${XBOX_V8_REVISION}/${assetName}`;
663
+ console.log(pc.green(`Downloading prebuilt V8 ${XBOX_V8_VERSION} (first time only) ...`));
664
+ console.log(url);
665
+ const response = await fetch(url);
666
+ if (!response.ok) {
667
+ throw new Error(`download failed: HTTP ${response.status}`);
668
+ }
669
+ fs.mkdirSync(cacheDir, { "recursive": true });
670
+ const zipPath = `${cacheDir}/${assetName}.tmp`;
671
+ fs.writeFileSync(zipPath, Buffer.from(await response.arrayBuffer()));
672
+ // Windows 10+ 標準の tar (bsdtar) は zip も展開できる
673
+ const extract = cp.spawnSync("tar", ["-xf", zipPath, "-C", cacheDir], { "stdio": "inherit" });
674
+ fs.rmSync(zipPath, { "force": true });
675
+ if (extract.status !== 0 || !fs.existsSync(`${cacheDir}/include/v8.h`)) {
676
+ fs.rmSync(cacheDir, { "recursive": true, "force": true });
677
+ throw new Error("failed to extract the prebuilt V8 archive");
678
+ }
679
+ console.log(pc.green(`Prebuilt V8 cached at: ${cacheDir}`));
680
+ return cacheDir;
681
+ };
583
682
  /**
584
683
  * @description Xbox(GDKネイティブ)用アプリの書き出し関数。
585
684
  * V8にNext2DのJSを載せ、Dawn(WebGPU/D3D12)で描画するC++ホストをビルドする。
@@ -619,18 +718,20 @@ const buildXbox = async () => {
619
718
  const gdkArch = process.env.NEXT2D_XBOX_ARCH || "Gaming.Xbox.Scarlett.x64";
620
719
  const cmakeBuildDir = `${process.cwd()}/${$outDir}/${platformDir}/build`;
621
720
  /**
622
- * prebuilt V8 monolith のパス。優先順: `--v8-root` 引数 > 環境変数 V8_ROOT。
623
- * どちらも無い場合は CMake (FindV8.cmake) が明確なエラーで停止するため、
624
- * ここでは事前に分かりやすく案内だけする。
721
+ * prebuilt V8 のパスを解決する (--v8-root > V8_ROOT > キャッシュ > 自動ダウンロード)。
722
+ * 通常は何も指定せずにビルドできる。
625
723
  */
626
- const resolvedV8Root = v8Root
627
- ? path.resolve(process.cwd(), v8Root)
628
- : process.env.V8_ROOT || "";
629
- if (!resolvedV8Root) {
630
- console.log(pc.red("V8 path is not specified."));
631
- console.log(pc.red("Pass `--v8-root <path>` (or set the V8_ROOT environment variable):"));
632
- console.log(pc.red(" npx @next2d/builder --platform xbox --env prd --v8-root C:\\path\\to\\v8"));
633
- console.log(pc.red(`The path must contain \`include/v8.h\` and \`lib/v8_monolith.lib\`. See ${XBOX_DIR_NAME}/README.md.`));
724
+ let resolvedV8Root = "";
725
+ try {
726
+ resolvedV8Root = await resolveXboxV8Root();
727
+ }
728
+ catch (error) {
729
+ console.log(pc.red(`Failed to prepare the prebuilt V8: ${error}`));
730
+ console.log(pc.red("Fallbacks:"));
731
+ console.log(pc.red(" 1) Retry later (the download may have failed temporarily)."));
732
+ console.log(pc.red(" 2) Build V8 yourself and pass `--v8-root <path>`:"));
733
+ console.log(pc.red(" npx @next2d/builder --platform xbox --env prd --v8-root C:\\path\\to\\v8"));
734
+ console.log(pc.red(` See ${XBOX_DIR_NAME}/README.md ("V8 の用意") for the build steps.`));
634
735
  return;
635
736
  }
636
737
  if (!fs.existsSync(`${resolvedV8Root}/include/v8.h`)) {
@@ -663,19 +764,22 @@ const buildXbox = async () => {
663
764
  ], { "stdio": "inherit" });
664
765
  return;
665
766
  }
666
- // フルビルド (Release パッケージまで)
667
- const stream = cp.spawn("cmake", [
668
- "--build", cmakeBuildDir,
669
- "--config", "Release"
670
- ], { "stdio": "inherit" });
671
- stream.on("close", (code) => {
672
- if (code !== 0) {
673
- console.log(pc.red("Export of the Xbox (GDK) package failed."));
674
- return;
675
- }
676
- console.log();
677
- console.log(pc.green(`Finished building the Xbox (GDK) package for ${gdkArch}.`));
678
- console.log();
767
+ // フルビルド (Release パッケージまで)。失敗時は reject して非ゼロ終了させる
768
+ // (以前は表示のみで exit code 0 のまま成功扱いになっていた)
769
+ await new Promise((resolve, reject) => {
770
+ const stream = cp.spawn("cmake", [
771
+ "--build", cmakeBuildDir,
772
+ "--config", "Release"
773
+ ], { "stdio": "inherit" });
774
+ stream.on("close", (code) => {
775
+ if (code !== 0) {
776
+ return reject("Export of the Xbox (GDK) package failed.");
777
+ }
778
+ console.log();
779
+ console.log(pc.green(`Finished building the Xbox (GDK) package for ${gdkArch}.`));
780
+ console.log();
781
+ resolve();
782
+ });
679
783
  });
680
784
  };
681
785
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@next2d/builder",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Multi-platform builder for Next2d Framework, supporting export to various platforms such as macOS, Windows, iOS, Android and Web(HTML)",
5
5
  "author": "Toshiyuki Ienaga <ienaga@next2d.app>",
6
6
  "license": "MIT",
@@ -22,6 +22,7 @@
22
22
  ],
23
23
  "scripts": {
24
24
  "lint": "eslint src/index.ts",
25
+ "prepare": "tsc",
25
26
  "release": "tsc"
26
27
  },
27
28
  "files": [
@@ -39,7 +40,7 @@
39
40
  "@electron-forge/core": "^7.11.2",
40
41
  "@types/node": "^26.1.0",
41
42
  "picocolors": "^1.1.1",
42
- "vite": "^8.1.2"
43
+ "vite": "^8.1.3"
43
44
  },
44
45
  "devDependencies": {
45
46
  "@eslint/eslintrc": "^3.3.5",
@@ -23,6 +23,18 @@ set(CMAKE_CXX_STANDARD 20)
23
23
  set(CMAKE_CXX_STANDARD_REQUIRED ON)
24
24
  set(CMAKE_CXX_EXTENSIONS OFF)
25
25
 
26
+ if(MSVC)
27
+ # MSVC は /Zc:__cplusplus を渡さないと __cplusplus を 199711L のまま報告し
28
+ # (/std:c++20 を指定していても)、v8config.h の C++20 チェックで停止する。
29
+ add_compile_options(/Zc:__cplusplus)
30
+ endif()
31
+
32
+ # CRT は静的 (/MT, Debug は /MTd) に統一する。
33
+ # prebuilt V8 monolith は GN の既定で静的 CRT ビルドのため、ホスト側が既定の /MD だと
34
+ # libcpmt.lib と msvcprt.lib が衝突して LNK2005/LNK2038 でリンクに失敗する。
35
+ # ここで設定することで FetchContent の Dawn も同じ CRT でビルドされる。
36
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
37
+
26
38
  # GDK target platform (Gaming.Xbox.* / Gaming.Desktop.*) の判定
27
39
  if(NOT DEFINED CMAKE_GENERATOR_PLATFORM)
28
40
  message(WARNING "CMAKE_GENERATOR_PLATFORM が未設定です。builder は -A Gaming.Xbox.Scarlett.x64 等を渡します。")
@@ -35,6 +47,28 @@ else()
35
47
  set(NEXT2D_IS_CONSOLE OFF)
36
48
  endif()
37
49
 
50
+ # -----------------------------------------------------------------------------
51
+ # GDK の解決 (2通り)
52
+ # A) インストール済み GDK: -A Gaming.Desktop.x64 / Gaming.Xbox.* でビルド。
53
+ # VS 統合が include/lib を自動供給するため追加設定は不要。
54
+ # B) 展開レイアウト (インストーラ不要・CI 向け): NuGet の Microsoft.GDK.Windows を
55
+ # 展開し、-A x64 + GDK_ROOT (cmake 変数 or 環境変数) で指定する。
56
+ # GDK_ROOT は <package>/native/<edition>/windows を指す (include/, lib/x64/, bin/x64/)。
57
+ # -----------------------------------------------------------------------------
58
+ string(FIND "${CMAKE_GENERATOR_PLATFORM}" "Gaming." _is_gaming_platform)
59
+ if(_is_gaming_platform LESS 0)
60
+ if(NOT DEFINED GDK_ROOT)
61
+ set(GDK_ROOT "$ENV{GDK_ROOT}")
62
+ endif()
63
+ if(NOT GDK_ROOT OR NOT EXISTS "${GDK_ROOT}/include/XGameRuntime.h")
64
+ message(FATAL_ERROR
65
+ "GDK が見つかりません。次のいずれかで指定してください:\n"
66
+ " 1) GDK をインストールして -A Gaming.Desktop.x64 でビルド\n"
67
+ " 2) NuGet の Microsoft.GDK.Windows を展開し、-A x64 で\n"
68
+ " -D GDK_ROOT=<package>/native/<edition>/windows (または環境変数 GDK_ROOT) を指定")
69
+ endif()
70
+ endif()
71
+
38
72
  # -----------------------------------------------------------------------------
39
73
  # 依存: Dawn (WebGPU 実装 / D3D12 バックエンド)
40
74
  # -----------------------------------------------------------------------------
@@ -61,11 +95,46 @@ target_include_directories(Next2DXboxHost PRIVATE
61
95
  "${CMAKE_CURRENT_SOURCE_DIR}/src"
62
96
  )
63
97
 
98
+ # 展開レイアウト (GDK_ROOT) 使用時: include/lib を明示指定し、実行時 DLL を並べる
99
+ if(_is_gaming_platform LESS 0)
100
+ target_include_directories(Next2DXboxHost PRIVATE "${GDK_ROOT}/include")
101
+ target_link_directories(Next2DXboxHost PRIVATE "${GDK_ROOT}/lib/x64")
102
+ add_custom_command(TARGET Next2DXboxHost POST_BUILD
103
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
104
+ "${GDK_ROOT}/bin/x64/xgameruntime.dll"
105
+ "$<TARGET_FILE_DIR:Next2DXboxHost>"
106
+ COMMENT "Staging xgameruntime.dll next to the executable")
107
+ endif()
108
+
64
109
  target_link_libraries(Next2DXboxHost PRIVATE
65
110
  v8::v8
66
111
  dawn::webgpu_dawn
67
112
  )
68
113
 
114
+ if(MSVC)
115
+ # CRT は静的 (/MT) に統一している (V8 monolith が静的 CRT 固定のため)。
116
+ # 一方 GDK の xgameruntime.lib 等は /MD ビルドで /DEFAULTLIB:msvcprt を
117
+ # 持ち込み LNK2005 (多重定義) を起こすので、動的 C++ ランタイムを除外して
118
+ # 静的側 (libcpmt) に一本化する。
119
+ target_link_options(Next2DXboxHost PRIVATE
120
+ /NODEFAULTLIB:msvcprt.lib
121
+ /NODEFAULTLIB:msvcprtd.lib
122
+ )
123
+
124
+ # Release でも PDB を生成する (クラッシュダンプ解析でスタックを名前解決するため)
125
+ target_compile_options(Next2DXboxHost PRIVATE /Zi)
126
+ target_link_options(Next2DXboxHost PRIVATE /DEBUG /OPT:REF /OPT:ICF)
127
+ endif()
128
+
129
+ # webgpu_dawn は SHARED (DLL)。実行に必要なため exe の隣へステージする
130
+ if(TARGET webgpu_dawn)
131
+ add_custom_command(TARGET Next2DXboxHost POST_BUILD
132
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
133
+ "$<TARGET_FILE:webgpu_dawn>"
134
+ "$<TARGET_FILE_DIR:Next2DXboxHost>"
135
+ COMMENT "Staging webgpu_dawn.dll next to the executable")
136
+ endif()
137
+
69
138
  # WebGPU / D3D12 / GameInput / WIC / XAudio2 / GDK
70
139
  target_link_libraries(Next2DXboxHost PRIVATE
71
140
  d3d12
@@ -92,10 +161,13 @@ else()
92
161
  target_compile_definitions(Next2DXboxHost PRIVATE NEXT2D_XBOX_CONSOLE=0)
93
162
  endif()
94
163
 
95
- # V8 のプラットフォーム要件
164
+ # V8 のプラットフォーム要件。
165
+ # prebuilt V8 (build-v8.yml) のビルドフラグと一致させること:
166
+ # V8_COMPRESS_POINTERS <-> v8_enable_pointer_compression=true
167
+ # sandbox は無効 (libc++ ハードニング必須のため use_custom_libcxx=false と両立しない)
168
+ # → V8_ENABLE_SANDBOX は定義しない
96
169
  target_compile_definitions(Next2DXboxHost PRIVATE
97
170
  V8_COMPRESS_POINTERS
98
- V8_ENABLE_SANDBOX
99
171
  NOMINMAX
100
172
  WIN32_LEAN_AND_MEAN
101
173
  UNICODE
@@ -51,7 +51,7 @@ C++ 実行ファイルをビルドします。Electron や WebView は使用し
51
51
  ### ランタイム環境の要点
52
52
 
53
53
  - **jitless V8**: Xbox/Switch のリテールは JIT(動的コード生成)を禁止するため、V8 は
54
- `--jitless`(Ignition インタプリタのみ)で起動する。WebAssembly も無効。
54
+ `--jitless --wasm-jitless` で起動する (JS=Ignition インタプリタ、wasm=DrumBrake インタープリタ)。
55
55
  - **Worker / OffscreenCanvas**: player はレンダラを Worker + `transferControlToOffscreen`
56
56
  で動かす。本ホストは **「同一 Isolate 内の別 Context を協調スケジューリングする単一スレッド
57
57
  Worker モデル」** を採用(`src/worker/WorkerRuntime`)。`postMessage` は V8 の
@@ -73,9 +73,9 @@ C++ 実行ファイルをビルドします。Electron や WebView は使用し
73
73
  |------|------|
74
74
  | OS | Windows 11 |
75
75
  | IDE | Visual Studio 2022 (v143, C++ Game development workload) |
76
- | GDK | Microsoft GDK (June 2024 以降) — ID@Xbox 登録が必要 |
76
+ | GDK | 公開版 GDK をインストール (`-A Gaming.Desktop.x64`)、**または** NuGet `Microsoft.GDK.Windows` を展開して `-A x64` + 環境変数/`-D` `GDK_ROOT=<pkg>/native/<edition>/windows`(インストーラ不要・CI 向け)。コンソール向け GDKX は ID@Xbox 登録が必要 |
77
77
  | CMake | 3.26 以降 |
78
- | V8 | prebuilt monolith (`v8_monolith.lib` + `include/`) |
78
+ | V8 | 不要 (builder が prebuilt を自動ダウンロード)。自前ビルドは `--v8-root` で指定可 |
79
79
  | Dawn | CMake の FetchContent で自動取得(ネットワーク必須) |
80
80
  | devkit | Xbox 開発機(実機検証用) |
81
81
 
@@ -83,25 +83,75 @@ C++ 実行ファイルをビルドします。Electron や WebView は使用し
83
83
 
84
84
  ## V8 の用意
85
85
 
86
- V8 はソースビルドが非常に重いため prebuilt monolith を使います。自前ビルド例:
86
+ **通常は何も必要ありません。** builder が Next2D の GitHub Releases から
87
+ prebuilt V8 monolith を自動ダウンロードし、`%LOCALAPPDATA%\next2d\v8\<version>` に
88
+ キャッシュします (マシンごとに初回のみ、以後は再利用)。
89
+
90
+ 自動ダウンロードを使わない場合の優先順:
91
+
92
+ 1. `--v8-root <path>` 引数
93
+ 2. 環境変数 `V8_ROOT`
94
+ 3. キャッシュ済み prebuilt
95
+ 4. GitHub Releases から自動ダウンロード
96
+
97
+ > prebuilt は builder リポジトリの `build-v8.yml` ワークフロー (windows-latest) で
98
+ > ビルドして Releases に発行しています。バージョンは builder の `XBOX_V8_VERSION` に固定。
99
+
100
+ ### 自前ビルドする場合 (任意)
101
+
102
+ コンソール実機向け (GDK ツールチェーン) や V8 バージョンを変えたい場合のみ。
103
+ **マシンごとに 1 回だけ**の作業で、以後は `--v8-root` で使い回せます。
104
+
105
+ 事前準備 (V8 ビルド用):
106
+
107
+ | 項目 | 内容 |
108
+ |------|------|
109
+ | ディスク | 約 40GB (ソース + ビルド生成物) |
110
+ | 時間 | 初回 fetch 30〜60 分 + ビルド 1〜3 時間 |
111
+ | Git | インストール済みであること |
112
+ | depot_tools | [取得手順](https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html#_setting_up)に従い展開し、**PATH の先頭**に追加 |
113
+ | 環境変数 | `DEPOT_TOOLS_WIN_TOOLCHAIN=0` (Google 社内ツールチェーンを使わない指定。未設定だと fetch が失敗する) |
114
+ | Windows SDK | Visual Studio Installer で「Windows 11 SDK」と「Windows 用デバッグツール」を含めること (GN が要求する) |
115
+
116
+ ビルド手順:
87
117
 
88
118
  ```bat
89
- :: depot_tools 導入後
119
+ set DEPOT_TOOLS_WIN_TOOLCHAIN=0
90
120
  fetch v8
91
121
  cd v8
92
- gn gen out\x64.release --args="v8_monolithic=true v8_use_external_startup_data=false is_component_build=false target_cpu=\"x64\" is_debug=false v8_enable_pointer_compression=true v8_enable_sandbox=true"
122
+ :: CI のコンパイル検証と同じバージョンに固定 (xbox-host-ci.yml の V8_TAG)
123
+ git checkout 13.7.152.19
124
+ gclient sync
125
+ gn gen out\x64.release --args="v8_monolithic=true v8_use_external_startup_data=false is_component_build=false use_custom_libcxx=false icu_use_data_file=false treat_warnings_as_errors=false v8_enable_drumbrake=true target_cpu=\"x64\" is_debug=false v8_enable_pointer_compression=true v8_enable_sandbox=false"
93
126
  ninja -C out\x64.release v8_monolith
94
127
  ```
95
128
 
96
129
  生成物を次の構成で配置し、builder の `--v8-root` 引数 (または環境変数 `V8_ROOT`) で指すこと:
97
130
 
98
131
  ```
99
- <V8_ROOT>/include/v8.h ...
100
- <V8_ROOT>/lib/v8_monolith.lib
132
+ <V8_ROOT>/include/v8.h ... (v8/include を丸ごとコピー)
133
+ <V8_ROOT>/lib/v8_monolith.lib (v8/out/x64.release/obj/v8_monolith.lib)
101
134
  ```
102
135
 
103
- > V8 のビルドフラグ(pointer compression / sandbox)は `CMakeLists.txt` の
104
- > `V8_COMPRESS_POINTERS` / `V8_ENABLE_SANDBOX` と一致させてください。不一致は ABI 崩れの原因になります。
136
+ > - `use_custom_libcxx=false` は必須。V8 は clang でビルドされるため、これを外すと
137
+ > V8 同梱の libc++ が使われ、MSVC (MS STL) でビルドする本ホストとリンクできません。
138
+ > - `v8_enable_sandbox=false` は必須。sandbox は libc++ ハードニング(=V8 同梱 libc++)を
139
+ > 要求するため `use_custom_libcxx=false` と両立しません (BUILD.gn の assert で停止)。
140
+ > 本ホストは自明に信頼済みのゲーム JS のみ実行するため無効で問題ありません。
141
+ > - `icu_use_data_file=false` を推奨。外すと実行時に `icudtl.dat` の同梱が必要になります。
142
+ > - `treat_warnings_as_errors=false` を推奨。`use_custom_libcxx=false` では MSVC STL の
143
+ > ヘッダ警告が -Werror で停止することがあります。**VS のバージョンは VS2022 (v143) を推奨**
144
+ > (新しすぎる STL は V8 の clang が警告/エラーを出しやすい)。
145
+ > - `v8_enable_drumbrake=true` は必須 (r2)。**DrumBrake = V8 の wasm インタープリタ**で、
146
+ > JIT 禁止環境 (コンソール) でも wasm を解釈実行できます。wasm はビルド時に turbofan を
147
+ > 要求するため `v8_jitless` ビルドは使えません — JIT の無効化はホストが実行時フラグ
148
+ > `--jitless --wasm-jitless` で行います (JS=Ignition / wasm=DrumBrake)。
149
+ > 注意: DrumBrake は既定ビルド対象外のためタグによりコンパイル不能な場合があります
150
+ > (13.6.233.17 は不可 → 13.7.152.19 で修正済み)。
151
+ > - pointer compression は `CMakeLists.txt` の `V8_COMPRESS_POINTERS` と一致させてください
152
+ > (sandbox 無効に合わせ `V8_ENABLE_SANDBOX` は定義しません)。不一致は ABI 崩れの原因になります。
153
+ > - 上記は PC (`Gaming.Desktop.x64`) 用。コンソール実機 (`Gaming.Xbox.*`) 向けは
154
+ > GDK ツールチェーンでの再ビルドが必要です (devkit 入手後の作業)。
105
155
 
106
156
  ---
107
157
 
@@ -110,7 +160,13 @@ ninja -C out\x64.release v8_monolith
110
160
  builder 経由(推奨):
111
161
 
112
162
  ```bat
113
- :: プロジェクトルートで。V8 は --v8-root で指定する (環境変数 V8_ROOT でも可)
163
+ :: プロジェクトルートで。V8 は初回に自動ダウンロードされる (指定不要)
164
+ npx @next2d/builder --platform xbox --env prd
165
+ ```
166
+
167
+ 自前の V8 を使う場合のみ `--v8-root` を指定:
168
+
169
+ ```bat
114
170
  npx @next2d/builder --platform xbox --env prd --v8-root C:\path\to\v8
115
171
  ```
116
172
 
@@ -157,7 +213,7 @@ macOS / Linux でそのまま実行できます:
157
213
  tests/check_local.sh
158
214
  ```
159
215
 
160
- 構文チェックは実 V8 ヘッダ (pin: `13.6.233.17`) に対して、Windows API 非依存の
216
+ 構文チェックは実 V8 ヘッダ (pin: `13.7.152.19`) に対して、Windows API 非依存の
161
217
  V8 バインディング 12 ファイルをコンパイル検証します (API 削除・型不整合を検出)。
162
218
 
163
219
  ### 2. GitHub Actions (windows-latest) — `.github/workflows/xbox-host-ci.yml`
@@ -249,6 +305,11 @@ player の実 API 使用を全面調査し、以下を実装済み。**この環
249
305
  | ポインタ/キーボード/ホイール入力 | ⚠️ 実装(要検証) | `WndProc`→`DispatchEvent`。配送先canvasの特定は実機検証 |
250
306
  | 動画 (HTMLVideoElement) | ⚠️ 実装(要検証) | `Video.cpp`(Media Foundation)。フレーム精度/音声同期は実機検証 |
251
307
  | クリップボード (`navigator.clipboard`) | ✅ 実装 | Win32 クリップボード (readText/writeText) |
308
+ | **JS エンジン/グローバル機能** (player 全数調査) | ✅ 実装 | Proxy=V8コア。`crypto.randomUUID`/`getRandomValues`(BCrypt)、`TextEncoder`/`TextDecoder`/`queueMicrotask`/`location`/`atob`/`btoa` は worker 含む全コンテキストへ注入。`createImageBitmap` は ImageData/ImageBitmap/canvas/Blob を受理 |
309
+ | **WebAssembly** | ✅ 実装 (要 V8 r2) | prebuilt V8 r2 = wasm + **DrumBrake**(V8 の wasm インタープリタ、JIT 禁止コンソール向け)。実行時 `--jitless --wasm-jitless` で JS=Ignition / wasm=DrumBrake 解釈実行 |
310
+ | **indexedDB** (最小実装) | ✅ 実装 | open/createObjectStore/transaction/get/put/delete/clear/getAll/count/keyPath。値は JSON 化可能なもの + ArrayBuffer/TypedArray(base64 永続化)。カーソル/インデックスは未対応。保存先 `%LOCALAPPDATA%\Next2D\idb_<db>.json` |
311
+ | **localStorage / sessionStorage** | ✅ 実装 | JS セマンティクス + ファイル永続化 (`%LOCALAPPDATA%\Next2D\`)。コンソール実機では XGameSave 化が必要 («EXTEND») |
312
+ | **Audio 要素** (`new Audio(url)`) | ✅ 実装 | play/pause/paused/loop/volume/currentTime/preload (pause→play は先頭から) |
252
313
 
253
314
  > player が使用する API はコード上すべて実装済み。残る唯一の障壁は
254
315
  > **GDK/devkit を要するコンパイル・実機検証**(この環境では物理的に不可)。
@@ -3,13 +3,18 @@
3
3
  # D3D12 バックエンドのみを有効化し、Xbox(GDK)/PC(GDK) で利用する。
4
4
  #
5
5
  # 注意:
6
- # - Dawn のビルドには depot_tools 由来の一部が不要になる CMake パスを使用する。
6
+ # - submodule はクローンしない (GIT_SUBMODULES "")。SwiftShader→LLVM まで再帰して
7
+ # 数 GB のクローン + Windows の MAX_PATH 超過 ("Filename too long") で失敗するため。
8
+ # 依存は Dawn 公式の DAWN_FETCH_DEPENDENCIES (python スクリプト) が必要分だけ取得する。
9
+ # - DAWN_FETCH_DEPENDENCIES には python3 が PATH に必要。
7
10
  # - 初回構成はネットワークとビルド時間を要する。CI ではキャッシュ推奨。
8
- # - DAWN_TAG は動作確認済みタグに固定すること (chromium ブランチに追従)。
11
+ # - DAWN_TAG はバインディング (bindings/webgpu/*) が使う API 世代と一致させること:
12
+ # wgpu::Limits / ShaderSourceWGSL / SurfaceSourceWindowsHWND / OptionalBool
13
+ # (いずれも 2025 以降の命名。古いタグでは SupportedLimits 等になりビルド不可)
9
14
  # =============================================================================
10
15
  include(FetchContent)
11
16
 
12
- set(DAWN_TAG "chromium/6478" CACHE STRING "Dawn のチェックアウトタグ")
17
+ set(DAWN_TAG "v20260402.171122" CACHE STRING "Dawn のチェックアウトタグ (github.com/google/dawn)")
13
18
 
14
19
  # Dawn のビルドオプション: 必要なものだけを有効化
15
20
  set(DAWN_FETCH_DEPENDENCIES ON CACHE BOOL "" FORCE)
@@ -24,14 +29,24 @@ set(DAWN_BUILD_SAMPLES OFF CACHE BOOL "" FORCE)
24
29
  set(TINT_BUILD_TESTS OFF CACHE BOOL "" FORCE)
25
30
  set(TINT_BUILD_CMD_TOOLS OFF CACHE BOOL "" FORCE)
26
31
 
27
- # webgpu_dawn: webgpu.h C-API を提供する統合ライブラリ (バインディング層はこれを叩く)
28
- set(DAWN_BUILD_MONOLITHIC_LIBRARY ON CACHE BOOL "" FORCE)
32
+ # webgpu_dawn: webgpu.h C-API を提供する統合ライブラリ (バインディング層はこれを叩く)。
33
+ # 2025 以降の Dawn では SHARED / STATIC / OFF の3値。
34
+ # SHARED (DLL) を選ぶ理由: V8 monolith と Dawn は双方が abseil を静的に内蔵しており、
35
+ # STATIC だと raw_hash_set 等の同名シンボルが LNK2005 で衝突する (しかも absl の
36
+ # バージョンが異なるため /FORCE:MULTIPLE は実行時破壊のリスクがある)。
37
+ # DLL にすれば公開されるのは WebGPU C API のみで、absl は DLL 内部に閉じる。
38
+ set(DAWN_BUILD_MONOLITHIC_LIBRARY SHARED CACHE STRING "" FORCE)
39
+ set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
29
40
 
30
41
  FetchContent_Declare(
31
42
  dawn
32
- GIT_REPOSITORY https://dawn.googlesource.com/dawn
43
+ # GitHub ミラーの方が CI から高速・安定 (googlesource はレート制限がきつい)
44
+ GIT_REPOSITORY https://github.com/google/dawn.git
33
45
  GIT_TAG ${DAWN_TAG}
34
46
  GIT_SHALLOW TRUE
47
+ # submodule は取得しない (DAWN_FETCH_DEPENDENCIES が必要分を取得する)
48
+ GIT_SUBMODULES ""
49
+ GIT_SUBMODULES_RECURSE FALSE
35
50
  )
36
51
 
37
52
  FetchContent_MakeAvailable(dawn)
@@ -40,3 +55,29 @@ FetchContent_MakeAvailable(dawn)
40
55
  if(NOT TARGET dawn::webgpu_dawn AND TARGET webgpu_dawn)
41
56
  add_library(dawn::webgpu_dawn ALIAS webgpu_dawn)
42
57
  endif()
58
+
59
+ # -----------------------------------------------------------------------------
60
+ # CRT を静的 (/MT) へ強制統一する。
61
+ # CMAKE_MSVC_RUNTIME_LIBRARY 変数だけでは Dawn の third_party (fetch_dawn_dependencies
62
+ # が取得する abseil/protobuf 等) の一部に伝播せず /MD が混ざり、静的 CRT 固定の
63
+ # prebuilt V8 とのリンクで LNK2005/LNK2019 になる。全ターゲットへ再帰的に
64
+ # プロパティを直接設定して確実に揃える。
65
+ # -----------------------------------------------------------------------------
66
+ function(next2d_force_static_crt dir)
67
+ get_property(_targets DIRECTORY "${dir}" PROPERTY BUILDSYSTEM_TARGETS)
68
+ foreach(_t IN LISTS _targets)
69
+ get_target_property(_type ${_t} TYPE)
70
+ if(NOT _type STREQUAL "INTERFACE_LIBRARY")
71
+ set_property(TARGET ${_t} PROPERTY
72
+ MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
73
+ endif()
74
+ endforeach()
75
+ get_property(_subdirs DIRECTORY "${dir}" PROPERTY SUBDIRECTORIES)
76
+ foreach(_sd IN LISTS _subdirs)
77
+ next2d_force_static_crt("${_sd}")
78
+ endforeach()
79
+ endfunction()
80
+
81
+ if(MSVC)
82
+ next2d_force_static_crt("${dawn_SOURCE_DIR}")
83
+ endif()