Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions .github/workflows/build-v8.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# V8 monolith (Windows x64) を GitHub Actions 上でビルドし、Releases へ発行する。
#
# 目的: ゲーム開発者が `npx @next2d/builder --platform xbox` を実行したとき、
# builder がここで発行した prebuilt を自動ダウンロードできるようにする
# (`--v8-root` / V8_ROOT の指定を不要にする)。
#
# 運用: 手動トリガー (Actions タブ → build-v8 → Run workflow)。
# バージョンを上げるときは v8_version を変えて実行し、src/index.ts の
# XBOX_V8_VERSION と xbox-host-ci.yml の V8_TAG を同じ値に更新する。
#
# 所要: 約 2〜4 時間 (V8 のフルビルド)。job 上限 6 時間以内。
name: build-v8

on:
workflow_dispatch:
inputs:
v8_version:
description: "V8 version tag (https://github.com/v8/v8/tags)"
required: true
default: "13.6.233.17"

permissions:
contents: write # Releases への発行に必要

jobs:
build-v8-windows-x64:
# windows-latest (VS2026/MSVC 14.5x) は STL が新しすぎて V8 の clang が
# -Werror で停止する。ホストの要件 (VS2022/v143, GDK) と同じ世代に固定する。
runs-on: windows-2022
timeout-minutes: 360
steps:
- name: Setup depot_tools
shell: pwsh
working-directory: ${{ runner.temp }}
run: |
git clone --depth 1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
Add-Content $env:GITHUB_PATH "$env:RUNNER_TEMP\depot_tools"
Add-Content $env:GITHUB_ENV "DEPOT_TOOLS_WIN_TOOLCHAIN=0"

- name: Fetch V8 ${{ inputs.v8_version }} (no history)
shell: cmd
working-directory: ${{ runner.temp }}
env:
V8_VERSION: ${{ inputs.v8_version }}
run: |
call fetch --no-history v8
if errorlevel 1 exit /b 1
cd v8
rem 重要: リビジョンは gclient に渡す。手動 git checkout だけだと
rem gclient sync が main へ戻してしまい、タグではなく main をビルドしてしまう。
call gclient sync -D --revision refs/tags/%V8_VERSION%
if errorlevel 1 exit /b 1

- name: Verify checked-out V8 version (fail fast)
shell: pwsh
working-directory: ${{ runner.temp }}/v8
run: |
# include/v8-version.h とタグの一致を検証する。
# 不一致のまま 2 時間ビルドして main 由来のエラーに悩まされるのを防ぐ。
$expected = "${{ inputs.v8_version }}"
$h = Get-Content include/v8-version.h -Raw
$maj = [regex]::Match($h, 'V8_MAJOR_VERSION (\d+)').Groups[1].Value
$min = [regex]::Match($h, 'V8_MINOR_VERSION (\d+)').Groups[1].Value
$bld = [regex]::Match($h, 'V8_BUILD_NUMBER (\d+)').Groups[1].Value
$pat = [regex]::Match($h, 'V8_PATCH_LEVEL (\d+)').Groups[1].Value
$actual = "$maj.$min.$bld.$pat"
if ($actual -ne $expected) {
Write-Error "V8 version mismatch: expected $expected but tree is $actual (gclient sync did not pin the tag)"
exit 1
}
Write-Host "OK: building V8 $actual"

- name: Build v8_monolith
shell: cmd
working-directory: ${{ runner.temp }}/v8
run: |
rem フラグはホスト側 (templates/xbox/CMakeLists.txt) の defines と一致させること:
rem v8_enable_pointer_compression <-> V8_COMPRESS_POINTERS
rem use_custom_libcxx=false : MSVC (MS STL) とのリンクに必須
rem v8_enable_sandbox=false : sandbox は libc++ ハードニング必須のため
rem use_custom_libcxx=false と両立しない (BUILD.gn の assert)。
rem ホストは自明に信頼済みのゲームJSのみ実行するため無効で問題ない。
rem v8_jitless=true + turbofan/wasm 無効 : ホストは実行時 --jitless (Xbox は JIT 禁止)。
rem BUILD.gn の assert により jitless では turbofan/sparkplug/maglev/wasm を
rem 無効にする必要がある (sparkplug/maglev は既定値が連動して自動で無効)。
rem MSVC STL と相性の悪い wasm 系ソースもビルド対象から外れる。
rem icu_use_data_file=false : icudtl.dat の同梱を不要にする
rem treat_warnings_as_errors=false : use_custom_libcxx=false では MSVC STL の
rem ヘッダ警告が -Werror で停止するため無効化
call 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_jitless=true v8_enable_turbofan=false v8_enable_webassembly=false target_cpu=\"x64\" is_debug=false v8_enable_pointer_compression=true v8_enable_sandbox=false"
if errorlevel 1 exit /b 1
call ninja -C out\x64.release v8_monolith
if errorlevel 1 (
echo.
echo ===== BUILD FAILED: retrying serially to surface the exact error =====
echo ===== -j 1 で再実行するため、このログの最後 = 失敗コマンドのエラー本体 =====
call ninja -C out\x64.release -j 1 v8_monolith
if errorlevel 1 exit /b 1
)

- name: Package (include/ + lib/v8_monolith.lib)
shell: pwsh
working-directory: ${{ runner.temp }}/v8
run: |
New-Item -ItemType Directory -Force package/lib | Out-Null
Copy-Item include package/include -Recurse
Copy-Item out/x64.release/obj/v8_monolith.lib package/lib/
Copy-Item out/x64.release/args.gn package/
"${{ inputs.v8_version }}" | Set-Content package/VERSION.txt
$zip = "$env:GITHUB_WORKSPACE/v8-monolith-${{ inputs.v8_version }}-windows-x64.zip"
Compress-Archive -Path package/* -DestinationPath $zip
Get-Item $zip | Select-Object Name, Length

- name: Publish to GitHub Releases
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
$tag = "v8-${{ inputs.v8_version }}-windows-x64"
$zip = "v8-monolith-${{ inputs.v8_version }}-windows-x64.zip"
$notes = @"
Prebuilt V8 monolith for the Next2D Xbox host (windows-x64).

- V8 ``${{ inputs.v8_version }}`` / VS2022 (windows-latest runner)
- gn args: monolithic, no external startup data, use_custom_libcxx=false,
icu_use_data_file=false, pointer compression enabled, sandbox disabled
(requires the bundled hardened libc++, conflicts with MSVC linking),
jitless (turbofan/sparkplug/maglev/wasm disabled — the host runs V8 with
--jitless because JIT is prohibited on Xbox)
- Layout: ``include/`` + ``lib/v8_monolith.lib`` (pass the extracted dir to ``--v8-root``)

``npx @next2d/builder --platform xbox`` downloads this automatically when
``--v8-root`` / ``V8_ROOT`` is not specified.
"@
# 既存タグなら差し替え、無ければ新規作成
gh release view $tag --repo ${{ github.repository }} 2>$null
if ($LASTEXITCODE -eq 0) {
gh release upload $tag $zip --clobber --repo ${{ github.repository }}
} else {
gh release create $tag $zip --title $tag --notes $notes --repo ${{ github.repository }}
}
12 changes: 7 additions & 5 deletions .github/workflows/xbox-host-ci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Xbox ホスト (templates/xbox) の CI。
#
# ローカルに Windows PC / GDK が無くても、GitHub Actions の windows-latest 上で
# 以下を検証する:
# ローカルに Windows PC / GDK が無くても、GitHub Actions の Windows ランナー
# (windows-2022 = VS2022/v143, GDK ビルドと同じ toolset) 上で以下を検証する:
# 1. raster-tests : Canvas2D ソフトラスタライザの単体テスト (Linux + Windows/MSVC)
# 2. windows-platform : WIC / DirectWrite / Media Foundation / XAudio2 の
# 実 API を Windows 上で実行する smoke テスト
Expand Down Expand Up @@ -42,7 +42,8 @@ jobs:

windows-tests:
name: RasterCore + Windows platform tests (MSVC)
runs-on: windows-latest
# VS2022 (v143) 世代に固定 — GDK ビルドの実ターゲットと同じ toolset で検証する
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
Expand Down Expand Up @@ -72,7 +73,8 @@ jobs:

v8-syntax-check:
name: V8-dependent sources compile check (MSVC)
runs-on: windows-latest
# VS2022 (v143) 世代に固定 — GDK ビルドの実ターゲットと同じ toolset で検証する
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
Expand Down Expand Up @@ -119,7 +121,7 @@ jobs:
# CMakeLists.txt と同じ定義でコンパイルのみ実行 (/c)。
cl /c /nologo /std:c++20 /Zc:__cplusplus /EHsc /W3 `
/DNOMINMAX /DWIN32_LEAN_AND_MEAN /DUNICODE /D_UNICODE `
/DV8_COMPRESS_POINTERS /DV8_ENABLE_SANDBOX `
/DV8_COMPRESS_POINTERS `
/Isrc /I"$v8inc" `
@files
if ($LASTEXITCODE -ne 0) { exit 1 }
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,13 @@ On other platforms the builder scaffolds the host project and stages assets only
See the generated `xbox/README.md` for full build steps.

```bat
npx @next2d/builder --platform xbox --env prd --v8-root C:\path\to\v8
npx @next2d/builder --platform xbox --env prd
```

The prebuilt V8 engine is downloaded automatically on the first Xbox build
(published from the `build-v8` workflow). To use your own build, pass
`--v8-root C:\path\to\v8`.

### Scheduled introduction

| platform |
Expand Down
105 changes: 91 additions & 14 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import pc from "picocolors";
import fs from "fs";
import os from "os";
import path from "path";
import { fileURLToPath } from "url";
import cp from "child_process";
Expand Down Expand Up @@ -95,8 +96,9 @@ const echoHelp = (): void =>
console.log("For preview example:");
console.log("npx @next2d/builder --preview --platform web --env prd");
console.log();
console.log("For Xbox build example (prebuilt V8 monolith path):");
console.log("npx @next2d/builder --platform xbox --env prd --v8-root C:\\path\\to\\v8");
console.log("For Xbox build example (prebuilt V8 is downloaded automatically):");
console.log("npx @next2d/builder --platform xbox --env prd");
console.log("To use your own V8 build: --v8-root C:\\path\\to\\v8");
console.log();
process.exit(1);
};
Expand Down Expand Up @@ -613,6 +615,18 @@ const getTemplateDir = (name: string): string =>
*/
const XBOX_CONFIG_NAME: string = "MicrosoftGame.config";

/**
* @description 自動ダウンロードする prebuilt V8 のバージョン。
* `.github/workflows/build-v8.yml` で発行した Releases のタグと、
* `xbox-host-ci.yml` の V8_TAG に一致させること。
* The prebuilt V8 version to auto-download. Must match the release tag
* published by `build-v8.yml` and V8_TAG in `xbox-host-ci.yml`.
*
* @type {string}
* @constant
*/
const XBOX_V8_VERSION: string = "13.6.233.17";

/**
* @description ゲーム側の `xbox/` へスキャフォールドしないテンプレート内ファイル。
* - MicrosoftGame.config : ゲーム固有設定 (injectGameConfig が注入)
Expand Down Expand Up @@ -735,6 +749,69 @@ const copyXboxResources = (): Promise<void> =>
});
};

/**
* @description Xbox ビルドに使う V8 のパスを解決する。優先順:
* 1. `--v8-root` 引数
* 2. 環境変数 `V8_ROOT`
* 3. キャッシュ済みの prebuilt (%LOCALAPPDATA%/next2d/v8/<version>)
* 4. GitHub Releases (build-v8.yml が発行) から自動ダウンロード
* 3・4 により、通常は何も指定せずに `--platform xbox` だけでビルドできる。
* Resolve the V8 path for the Xbox build. With the cached/auto-downloaded
* prebuilt, no flag or env var is required in the common case.
*
* @return {Promise<string>}
* @method
* @public
*/
const resolveXboxV8Root = async (): Promise<string> =>
{
// 1. --v8-root 引数
if (v8Root) {
return path.resolve(process.cwd(), v8Root);
}

// 2. 環境変数 V8_ROOT
if (process.env.V8_ROOT) {
return process.env.V8_ROOT;
}

// 3. キャッシュ済み prebuilt
const cacheBase: string = process.env.LOCALAPPDATA
? `${process.env.LOCALAPPDATA}/next2d`
: `${os.homedir()}/.cache/next2d`;
const cacheDir: string = `${cacheBase}/v8/${XBOX_V8_VERSION}`;
if (fs.existsSync(`${cacheDir}/include/v8.h`)) {
return cacheDir;
}

// 4. GitHub Releases から自動ダウンロード (マシンごとに初回のみ)
const assetName: string = `v8-monolith-${XBOX_V8_VERSION}-windows-x64.zip`;
const url: string = `https://github.com/Next2D/builder/releases/download/v8-${XBOX_V8_VERSION}-windows-x64/${assetName}`;

console.log(pc.green(`Downloading prebuilt V8 ${XBOX_V8_VERSION} (first time only) ...`));
console.log(url);

const response = await fetch(url);
if (!response.ok) {
throw new Error(`download failed: HTTP ${response.status}`);
}

fs.mkdirSync(cacheDir, { "recursive": true });
const zipPath: string = `${cacheDir}/${assetName}.tmp`;
fs.writeFileSync(zipPath, Buffer.from(await response.arrayBuffer()));

// Windows 10+ 標準の tar (bsdtar) は zip も展開できる
const extract = cp.spawnSync("tar", ["-xf", zipPath, "-C", cacheDir], { "stdio": "inherit" });
fs.rmSync(zipPath, { "force": true });
if (extract.status !== 0 || !fs.existsSync(`${cacheDir}/include/v8.h`)) {
fs.rmSync(cacheDir, { "recursive": true, "force": true });
throw new Error("failed to extract the prebuilt V8 archive");
}

console.log(pc.green(`Prebuilt V8 cached at: ${cacheDir}`));
return cacheDir;
};

/**
* @description Xbox(GDKネイティブ)用アプリの書き出し関数。
* V8にNext2DのJSを載せ、Dawn(WebGPU/D3D12)で描画するC++ホストをビルドする。
Expand Down Expand Up @@ -778,19 +855,19 @@ const buildXbox = async (): Promise<void> =>
const cmakeBuildDir: string = `${process.cwd()}/${$outDir}/${platformDir}/build`;

/**
* prebuilt V8 monolith のパス。優先順: `--v8-root` 引数 > 環境変数 V8_ROOT。
* どちらも無い場合は CMake (FindV8.cmake) が明確なエラーで停止するため、
* ここでは事前に分かりやすく案内だけする。
* prebuilt V8 のパスを解決する (--v8-root > V8_ROOT > キャッシュ > 自動ダウンロード)。
* 通常は何も指定せずにビルドできる。
*/
const resolvedV8Root: string = v8Root
? path.resolve(process.cwd(), v8Root)
: process.env.V8_ROOT || "";

if (!resolvedV8Root) {
console.log(pc.red("V8 path is not specified."));
console.log(pc.red("Pass `--v8-root <path>` (or set the V8_ROOT environment variable):"));
console.log(pc.red(" npx @next2d/builder --platform xbox --env prd --v8-root C:\\path\\to\\v8"));
console.log(pc.red(`The path must contain \`include/v8.h\` and \`lib/v8_monolith.lib\`. See ${XBOX_DIR_NAME}/README.md.`));
let resolvedV8Root: string = "";
try {
resolvedV8Root = await resolveXboxV8Root();
} catch (error) {
console.log(pc.red(`Failed to prepare the prebuilt V8: ${error}`));
console.log(pc.red("Fallbacks:"));
console.log(pc.red(" 1) Retry later (the download may have failed temporarily)."));
console.log(pc.red(" 2) Build V8 yourself and pass `--v8-root <path>`:"));
console.log(pc.red(" npx @next2d/builder --platform xbox --env prd --v8-root C:\\path\\to\\v8"));
console.log(pc.red(` See ${XBOX_DIR_NAME}/README.md ("V8 の用意") for the build steps.`));
return;
}
if (!fs.existsSync(`${resolvedV8Root}/include/v8.h`)) {
Expand Down
7 changes: 5 additions & 2 deletions templates/xbox/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,13 @@ else()
target_compile_definitions(Next2DXboxHost PRIVATE NEXT2D_XBOX_CONSOLE=0)
endif()

# V8 のプラットフォーム要件
# V8 のプラットフォーム要件。
# prebuilt V8 (build-v8.yml) のビルドフラグと一致させること:
# V8_COMPRESS_POINTERS <-> v8_enable_pointer_compression=true
# sandbox は無効 (libc++ ハードニング必須のため use_custom_libcxx=false と両立しない)
# → V8_ENABLE_SANDBOX は定義しない
target_compile_definitions(Next2DXboxHost PRIVATE
V8_COMPRESS_POINTERS
V8_ENABLE_SANDBOX
NOMINMAX
WIN32_LEAN_AND_MEAN
UNICODE
Expand Down
Loading
Loading