From d1f77f5a37e542f384b393c80fed255c2801709c Mon Sep 17 00:00:00 2001 From: L-Sun Date: Sat, 24 Oct 2026 18:50:17 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=F0=9F=91=B7=20[ci]=20use=20maintained=20Vu?= =?UTF-8?q?lkan=20SDK=20installer=20action?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/macos.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/macos.yaml b/.github/workflows/macos.yaml index 647b6b85..9eee5275 100644 --- a/.github/workflows/macos.yaml +++ b/.github/workflows/macos.yaml @@ -63,10 +63,9 @@ jobs: # Headers/Loader alone are insufficient: the engine also links Slang and # SPIRV-Cross. Install the complete prebuilt SDK, including those libraries. - name: Install Vulkan SDK - # v1.2 predates the vulkansdk-macOS-.app installer layout. - uses: humbletim/install-vulkan-sdk@e7d6e7b937bde4503c7ba5c9584c9dc68f44c4b8 + uses: jakoch/install-vulkan-sdk-action@v1.7.0 with: - version: ${{ env.VULKAN_SDK_VERSION }} + vulkan_version: ${{ env.VULKAN_SDK_VERSION }} cache: true - name: Check SDK components From 6b6f234a2050934be324b5dc20b345395042ac9b Mon Sep 17 00:00:00 2001 From: L-Sun Date: Sat, 24 Oct 2026 18:55:50 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=F0=9F=91=B7=20[ci]=20unify=20Windows=20and?= =?UTF-8?q?=20macOS=20builds=20in=20one=20matrix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yaml | 184 +++++++++++++++++++++++++++++++++ .github/workflows/macos.yaml | 116 --------------------- .github/workflows/windows.yaml | 94 ----------------- README.md | 11 +- 4 files changed, 188 insertions(+), 217 deletions(-) create mode 100644 .github/workflows/build.yaml delete mode 100644 .github/workflows/macos.yaml delete mode 100644 .github/workflows/windows.yaml diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 00000000..9ca11ebd --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,184 @@ +name: build +on: + workflow_dispatch: + pull_request: + branches: [dev] + paths-ignore: &docs-only + - "**/*.md" + - "docs/**" + - "tools/**" + - "LICENSE" + - ".cursor/**" + - ".codex/**" + - ".vscode/**" + - ".clang-format" + - ".clangd" + push: + branches: [dev] + paths-ignore: *docs-only + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + timeout-minutes: ${{ matrix.timeout }} + strategy: + fail-fast: false + matrix: + include: + - name: Windows clang-cl + os: windows-latest + platform: windows + arch: x64 + toolchain: clang-cl + timeout: 180 + - name: Windows MSVC + os: windows-latest + platform: windows + arch: x64 + toolchain: msvc + timeout: 180 + - name: macOS ARM64 clang + os: macos-26 + platform: macosx + arch: arm64 + toolchain: clang + timeout: 90 + env: + LLVM_VERSION: "23.1.2" + VULKAN_SDK_VERSION: "1.4.363.0" + CMAKE_BUILD_PARALLEL_LEVEL: "3" + CARGO_BUILD_JOBS: "1" + defaults: + run: + shell: bash + + steps: + - uses: actions/checkout@v4 + with: + lfs: true + + # Keep the package root short, especially for USD on Windows. + - name: Set xmake global directory + run: echo "XMAKE_GLOBALDIR=$RUNNER_WORKSPACE/xmake-global" >> "$GITHUB_ENV" + + - name: Install LLVM + if: ${{ matrix.toolchain == 'clang-cl' }} + shell: pwsh + run: | + Invoke-WebRequest -Uri "https://github.com/llvm/llvm-project/releases/download/llvmorg-$env:LLVM_VERSION/LLVM-$env:LLVM_VERSION-win64.msi" -OutFile "llvm.msi" + if (Test-Path "C:\Program Files\LLVM") { Remove-Item -Recurse -Force "C:\Program Files\LLVM" } + $process = Start-Process msiexec.exe -ArgumentList "/i", "`"$((Resolve-Path llvm.msi).Path)`"", "/qn", "/norestart" -Wait -PassThru + if ($process.ExitCode -ne 0) { throw "LLVM installer failed with exit code $($process.ExitCode)" } + $version = & "C:\Program Files\LLVM\bin\clang-cl.exe" --version + $version + if (-not ($version -match "clang version $([regex]::Escape($env:LLVM_VERSION))")) { throw "Unexpected clang-cl version" } + + - name: Download ISPC (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + Invoke-WebRequest -Uri "https://github.com/ispc/ispc/releases/download/v1.27.0/ispc-v1.27.0-windows.zip" -OutFile "ispc.zip" + 7z x ispc.zip + "$env:GITHUB_WORKSPACE\ispc-v1.27.0-windows\bin" >> $env:GITHUB_PATH + + - name: Install build tools (macOS) + if: runner.os == 'macOS' + run: | + brew install llvm ispc cmake ninja + llvm_root="$(brew --prefix llvm)" + echo "LLVM_ROOT=$llvm_root" >> "$GITHUB_ENV" + echo "$llvm_root/bin" >> "$GITHUB_PATH" + "$llvm_root/bin/clang++" --version + ispc --version + cargo --version + + - uses: oven-sh/setup-bun@v2 + with: + bun-version: "1.4.2" + + # Headers/Loader alone are insufficient: the engine also links Slang and + # SPIRV-Cross. Install the complete prebuilt SDK, including those libraries. + - name: Install Vulkan SDK + uses: jakoch/install-vulkan-sdk-action@v1.7.0 + with: + vulkan_version: ${{ env.VULKAN_SDK_VERSION }} + cache: true + + - name: Check SDK components (macOS) + if: runner.os == 'macOS' + run: | + test -f "$VULKAN_SDK/include/vulkan/vulkan.cppm" + test -f "$VULKAN_SDK/include/slang/slang.h" + test -f "$VULKAN_SDK/lib/libslang.dylib" + for component in core glsl msl; do + test -f "$VULKAN_SDK/lib/libspirv-cross-$component.a" + done + + - uses: xmake-io/github-action-setup-xmake@v1 + with: + xmake-version: L-Sun/xmake#branch@hitagi-engine + actions-cache-folder: ".xmake-cache" + + - name: Record tool versions + id: tools + run: | + # Include resolved versions in cache keys, even as runner images change. + { + xmake --version + rustc --version + bun --version + if [[ "$RUNNER_OS" == "macOS" ]]; then + "$LLVM_ROOT/bin/clang++" --version + elif [[ "${{ matrix.toolchain }}" == "clang-cl" ]]; then + "/c/Program Files/LLVM/bin/clang-cl.exe" --version + else + "/c/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe" -latest -property installationVersion + fi + } > tool-versions.txt + cat tool-versions.txt + echo "hash=$(node -e "process.stdout.write(require('crypto').createHash('sha256').update(require('fs').readFileSync('tool-versions.txt')).digest('hex'))")" >> "$GITHUB_OUTPUT" + + - name: Restore xmake packages + id: restore-packages + uses: actions/cache/restore@v4 + with: + path: ${{ env.XMAKE_GLOBALDIR }}/.xmake/packages + key: xmake-packages-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.toolchain }}-release-${{ steps.tools.outputs.hash }}-sdk${{ env.VULKAN_SDK_VERSION }}-${{ hashFiles('.github/workflows/build.yaml', 'xmake.lua', 'hitagi/**/xmake.lua', 'xmake/**') }} + + - name: Configure + run: | + compiler_args=() + if [[ "$RUNNER_OS" == "macOS" ]]; then + # Native clang preserves its default deployment target, unlike the + # llvm toolchain, which injects Xcode target flags. + compiler_args=(--cc="$LLVM_ROOT/bin/clang" --cxx="$LLVM_ROOT/bin/clang++") + fi + xmake f -y -p ${{ matrix.platform }} -a ${{ matrix.arch }} -m release \ + --toolchain=${{ matrix.toolchain }} "${compiler_args[@]}" \ + --ispc=y --profile=n --benchmarks=n + + - name: Save xmake packages + if: ${{ success() && steps.restore-packages.outputs.cache-hit != 'true' }} + uses: actions/cache/save@v4 + with: + path: ${{ env.XMAKE_GLOBALDIR }}/.xmake/packages + key: ${{ steps.restore-packages.outputs.cache-primary-key }} + + - name: Build libraries, tests and examples + run: xmake -vD -j 3 + + - name: Upload dependency failure logs + if: ${{ failure() }} + uses: actions/upload-artifact@v4 + with: + name: dependency-failure-logs-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.toolchain }} + path: ${{ env.XMAKE_GLOBALDIR }}/.xmake/cache/packages/**/installdir.failed/logs/** + if-no-files-found: ignore diff --git a/.github/workflows/macos.yaml b/.github/workflows/macos.yaml deleted file mode 100644 index 9eee5275..00000000 --- a/.github/workflows/macos.yaml +++ /dev/null @@ -1,116 +0,0 @@ -name: macos-build -on: - workflow_dispatch: - pull_request: - branches: [dev] - paths-ignore: &docs-only - - "**/*.md" - - "docs/**" - - "tools/**" - - "LICENSE" - - ".cursor/**" - - ".codex/**" - - ".vscode/**" - - ".clang-format" - - ".clangd" - push: - branches: [dev] - paths-ignore: *docs-only - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - build: - # Match the native Apple Silicon / Metal 26 development environment. - runs-on: macos-26 - timeout-minutes: 90 - env: - VULKAN_SDK_VERSION: "1.4.363.0" - CMAKE_BUILD_PARALLEL_LEVEL: "3" - CARGO_BUILD_JOBS: "1" - defaults: - run: - shell: bash - - steps: - - uses: actions/checkout@v4 - with: - lfs: true - - - name: Install build tools - id: tools - run: | - brew install llvm ispc cmake ninja - llvm_root="$(brew --prefix llvm)" - echo "LLVM_ROOT=$llvm_root" >> "$GITHUB_ENV" - echo "$llvm_root/bin" >> "$GITHUB_PATH" - echo "XMAKE_GLOBALDIR=$RUNNER_WORKSPACE/xmake-global" >> "$GITHUB_ENV" - "$llvm_root/bin/clang++" --version - ispc --version - cargo --version - echo "llvm=$("$llvm_root/bin/clang++" -dumpversion)" >> "$GITHUB_OUTPUT" - echo "rust=$(rustc --version | shasum -a 256 | cut -d ' ' -f 1)" >> "$GITHUB_OUTPUT" - - - uses: oven-sh/setup-bun@v2 - with: - bun-version: "1.4.2" - - # Headers/Loader alone are insufficient: the engine also links Slang and - # SPIRV-Cross. Install the complete prebuilt SDK, including those libraries. - - name: Install Vulkan SDK - uses: jakoch/install-vulkan-sdk-action@v1.7.0 - with: - vulkan_version: ${{ env.VULKAN_SDK_VERSION }} - cache: true - - - name: Check SDK components - run: | - test -f "$VULKAN_SDK/include/vulkan/vulkan.cppm" - test -f "$VULKAN_SDK/include/slang/slang.h" - test -f "$VULKAN_SDK/lib/libslang.dylib" - for component in core glsl msl; do - test -f "$VULKAN_SDK/lib/libspirv-cross-$component.a" - done - - - uses: xmake-io/github-action-setup-xmake@v1 - with: - xmake-version: L-Sun/xmake#branch@hitagi-engine - actions-cache-folder: ".xmake-cache" - - - name: Restore xmake packages - id: restore-packages - uses: actions/cache/restore@v4 - with: - path: ${{ env.XMAKE_GLOBALDIR }}/.xmake/packages - key: xmake-packages-macos-26-${{ runner.arch }}-release-llvm${{ steps.tools.outputs.llvm }}-rust${{ steps.tools.outputs.rust }}-sdk${{ env.VULKAN_SDK_VERSION }}-${{ hashFiles('.github/workflows/macos.yaml', 'xmake.lua', 'hitagi/**/xmake.lua', 'xmake/**') }} - - - name: Configure - run: | - # Native clang preserves its default macOS target; the llvm toolchain - # injects Xcode target flags and is not equivalent for C++23 modules. - xmake f -y -p macosx -a arm64 -m release --toolchain=clang \ - --cc="$LLVM_ROOT/bin/clang" --cxx="$LLVM_ROOT/bin/clang++" \ - --ispc=y --profile=n --benchmarks=n - - - name: Save xmake packages - if: ${{ success() && steps.restore-packages.outputs.cache-hit != 'true' }} - uses: actions/cache/save@v4 - with: - path: ${{ env.XMAKE_GLOBALDIR }}/.xmake/packages - key: ${{ steps.restore-packages.outputs.cache-primary-key }} - - - name: Build libraries, tests and examples - run: xmake -vD -j 3 - - - name: Upload dependency failure logs - if: ${{ failure() }} - uses: actions/upload-artifact@v4 - with: - name: macos-dependency-failure-logs - path: ${{ env.XMAKE_GLOBALDIR }}/.xmake/cache/packages/**/installdir.failed/logs/** - if-no-files-found: ignore diff --git a/.github/workflows/windows.yaml b/.github/workflows/windows.yaml deleted file mode 100644 index 7fbfe229..00000000 --- a/.github/workflows/windows.yaml +++ /dev/null @@ -1,94 +0,0 @@ -name: windows-build -on: - workflow_dispatch: - pull_request: - branches: [dev] - paths-ignore: &docs-only - - "**/*.md" - - "docs/**" - - "tools/**" - - "LICENSE" - - ".cursor/**" - - ".codex/**" - - ".vscode/**" - - ".clang-format" - - ".clangd" - push: - branches: [dev] - paths-ignore: *docs-only - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - build: - runs-on: ${{ matrix.os }} - env: - LLVM_VERSION: "23.1.2" - - strategy: - matrix: - os: [windows-latest] - compiler: ["--toolchain=clang-cl", "--toolchain=msvc"] - - steps: - - uses: actions/checkout@v4 - - # Keep the package root short; USD install paths are long on Windows. - - name: Set xmake global directory - run: | - "XMAKE_GLOBALDIR=$env:RUNNER_WORKSPACE\xmake-global" >> $env:GITHUB_ENV - - - name: Install LLVM - if: ${{ matrix.compiler == '--toolchain=clang-cl' }} - run: | - Invoke-WebRequest -Uri "https://github.com/llvm/llvm-project/releases/download/llvmorg-$env:LLVM_VERSION/LLVM-$env:LLVM_VERSION-win64.msi" -OutFile "llvm.msi" - if (Test-Path "C:\Program Files\LLVM") { Remove-Item -Recurse -Force "C:\Program Files\LLVM" } - $process = Start-Process msiexec.exe -ArgumentList "/i", "`"$((Resolve-Path llvm.msi).Path)`"", "/qn", "/norestart" -Wait -PassThru - if ($process.ExitCode -ne 0) { throw "LLVM installer failed with exit code $($process.ExitCode)" } - $version = & "C:\Program Files\LLVM\bin\clang-cl.exe" --version - $version - if (-not ($version -match "clang version $([regex]::Escape($env:LLVM_VERSION))")) { throw "Unexpected clang-cl version" } - - - name: Download ISPC (Windows) - run: | - Invoke-WebRequest -Uri "https://github.com/ispc/ispc/releases/download/v1.27.0/ispc-v1.27.0-windows.zip" -OutFile "ispc.zip" - 7z x ispc.zip - "ispc-v1.27.0-windows/bin" >> $env:GITHUB_PATH - - - name: Setup Vulkan SDK - uses: humbletim/setup-vulkan-sdk@v1.2.1 - with: - vulkan-query-version: latest - vulkan-components: Vulkan-Headers, Vulkan-Loader - vulkan-use-cache: true - - - uses: xmake-io/github-action-setup-xmake@v1 - with: - xmake-version: L-Sun/xmake#branch@hitagi-engine - actions-cache-folder: ".xmake-cache" - - - name: Restore xmake packages - id: restore-packages - uses: actions/cache/restore@v4 - with: - path: ${{ env.XMAKE_GLOBALDIR }}/.xmake/packages - key: xmake-packages-${{ runner.os }}-${{ matrix.compiler }}-${{ hashFiles('xmake.lua', 'hitagi/**/xmake.lua', 'xmake/packages/**') }} - restore-keys: | - xmake-packages-${{ runner.os }}-${{ matrix.compiler }}- - - - name: Config - run: | - xmake f -y -a x64 -m release ${{ matrix.compiler }} - - - name: Save xmake packages - if: ${{ !cancelled() && steps.restore-packages.outputs.cache-hit != 'true' }} - uses: actions/cache/save@v4 - with: - path: ${{ env.XMAKE_GLOBALDIR }}/.xmake/packages - key: ${{ steps.restore-packages.outputs.cache-primary-key }} - - - name: Build - run: | - xmake -vD diff --git a/README.md b/README.md index 42d7d54e..5035850b 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,8 @@

Hitagi Engine

- - GitHub Workflow Status - - - macOS Workflow Status + + Build Status (Windows and macOS)

@@ -26,7 +23,7 @@ Hitagi Engine is an experimental game engine written with C++23 modules and buil - **Platform**: Win32 on Windows, SDL3 elsewhere - **Asset authoring**: OpenUSD import, material source metadata, renderer-agnostic material graph compilation against renderer-supplied pass templates, and asset cooking -Platform status: Windows is the primary target. CI workflows cover Windows builds and macOS 26 ARM64 release builds. The macOS workflow compiles test targets but does not run tests. Linux/Wayland code paths exist for Vulkan and SDL3 but are not regularly validated. +Platform status: Windows is the primary target. One CI workflow uses a matrix for Windows clang-cl, Windows MSVC and macOS 26 ARM64 clang release builds. It compiles test targets but does not run tests. Linux/Wayland code paths exist for Vulkan and SDL3 but are not regularly validated. ## Repository Layout @@ -68,7 +65,7 @@ xmake f -y -p macosx -a arm64 -m release --toolchain=clang \ xmake build -j 3 ``` -Use the native `clang` toolchain, preserving its default deployment target; XMake's `llvm` toolchain injects different Xcode target flags. The macOS workflow installs prerequisites, caches packages by compiler/Rust/SDK versions and package recipes, builds libraries/tests/examples without running tests. It runs for pushes and pull requests to `dev` and can be dispatched manually. These steps require the macOS platform implementation and package recipes to be present in the checked-out revision. +Use the native `clang` toolchain, preserving its default deployment target; XMake's `llvm` toolchain injects different Xcode target flags. The build workflow installs prerequisites, caches packages by compiler/Rust/SDK versions and package recipes, builds libraries/tests/examples without running tests. It runs for pushes and pull requests to `dev` and can be dispatched manually. These steps require the macOS platform implementation and package recipes to be present in the checked-out revision. On Windows: From 9091c96861f1bb541d822e4554819c8e24061c25 Mon Sep 17 00:00:00 2001 From: L-Sun Date: Sat, 24 Oct 2026 19:20:32 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=F0=9F=91=B7=20[ci]=20remove=20redundant=20?= =?UTF-8?q?macOS=20SDK=20component=20checks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yaml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 9ca11ebd..04609188 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -112,16 +112,6 @@ jobs: vulkan_version: ${{ env.VULKAN_SDK_VERSION }} cache: true - - name: Check SDK components (macOS) - if: runner.os == 'macOS' - run: | - test -f "$VULKAN_SDK/include/vulkan/vulkan.cppm" - test -f "$VULKAN_SDK/include/slang/slang.h" - test -f "$VULKAN_SDK/lib/libslang.dylib" - for component in core glsl msl; do - test -f "$VULKAN_SDK/lib/libspirv-cross-$component.a" - done - - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: L-Sun/xmake#branch@hitagi-engine From 0a26c581559526234b768c2cae59601f64b7b47f Mon Sep 17 00:00:00 2001 From: L-Sun Date: Sat, 24 Oct 2026 19:25:08 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=F0=9F=91=B7=20[ci]=20import=20platform=20c?= =?UTF-8?q?onfigs=20and=20use=20default=20build=20behavior?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/configs/macos-arm64.conf | 12 ++++++++++++ .github/configs/windows-clang.conf | 9 +++++++++ .github/configs/windows-msvc.conf | 9 +++++++++ .github/workflows/build.yaml | 20 ++++++-------------- README.md | 2 ++ 5 files changed, 38 insertions(+), 14 deletions(-) create mode 100644 .github/configs/macos-arm64.conf create mode 100644 .github/configs/windows-clang.conf create mode 100644 .github/configs/windows-msvc.conf diff --git a/.github/configs/macos-arm64.conf b/.github/configs/macos-arm64.conf new file mode 100644 index 00000000..775fc7ed --- /dev/null +++ b/.github/configs/macos-arm64.conf @@ -0,0 +1,12 @@ +{ + plat = "macosx", + arch = "arm64", + mode = "release", + toolchain = "clang", + -- Homebrew LLVM is added to PATH by the workflow. + cc = "clang", + cxx = "clang++", + ispc = true, + profile = false, + benchmarks = false +} diff --git a/.github/configs/windows-clang.conf b/.github/configs/windows-clang.conf new file mode 100644 index 00000000..8ce1823f --- /dev/null +++ b/.github/configs/windows-clang.conf @@ -0,0 +1,9 @@ +{ + plat = "windows", + arch = "x64", + mode = "release", + toolchain = "clang-cl", + ispc = true, + profile = false, + benchmarks = false +} diff --git a/.github/configs/windows-msvc.conf b/.github/configs/windows-msvc.conf new file mode 100644 index 00000000..ac3a3ccb --- /dev/null +++ b/.github/configs/windows-msvc.conf @@ -0,0 +1,9 @@ +{ + plat = "windows", + arch = "x64", + mode = "release", + toolchain = "msvc", + ispc = true, + profile = false, + benchmarks = false +} diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 04609188..b6bf4e19 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -38,24 +38,25 @@ jobs: platform: windows arch: x64 toolchain: clang-cl + config: windows-clang timeout: 180 - name: Windows MSVC os: windows-latest platform: windows arch: x64 toolchain: msvc + config: windows-msvc timeout: 180 - name: macOS ARM64 clang os: macos-26 platform: macosx arch: arm64 toolchain: clang + config: macos-arm64 timeout: 90 env: LLVM_VERSION: "23.1.2" VULKAN_SDK_VERSION: "1.4.363.0" - CMAKE_BUILD_PARALLEL_LEVEL: "3" - CARGO_BUILD_JOBS: "1" defaults: run: shell: bash @@ -141,19 +142,10 @@ jobs: uses: actions/cache/restore@v4 with: path: ${{ env.XMAKE_GLOBALDIR }}/.xmake/packages - key: xmake-packages-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.toolchain }}-release-${{ steps.tools.outputs.hash }}-sdk${{ env.VULKAN_SDK_VERSION }}-${{ hashFiles('.github/workflows/build.yaml', 'xmake.lua', 'hitagi/**/xmake.lua', 'xmake/**') }} + key: xmake-packages-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.toolchain }}-release-${{ steps.tools.outputs.hash }}-sdk${{ env.VULKAN_SDK_VERSION }}-${{ hashFiles('.github/workflows/build.yaml', '.github/configs/*.conf', 'xmake.lua', 'hitagi/**/xmake.lua', 'xmake/**') }} - name: Configure - run: | - compiler_args=() - if [[ "$RUNNER_OS" == "macOS" ]]; then - # Native clang preserves its default deployment target, unlike the - # llvm toolchain, which injects Xcode target flags. - compiler_args=(--cc="$LLVM_ROOT/bin/clang" --cxx="$LLVM_ROOT/bin/clang++") - fi - xmake f -y -p ${{ matrix.platform }} -a ${{ matrix.arch }} -m release \ - --toolchain=${{ matrix.toolchain }} "${compiler_args[@]}" \ - --ispc=y --profile=n --benchmarks=n + run: xmake f -y --import=.github/configs/${{ matrix.config }}.conf - name: Save xmake packages if: ${{ success() && steps.restore-packages.outputs.cache-hit != 'true' }} @@ -163,7 +155,7 @@ jobs: key: ${{ steps.restore-packages.outputs.cache-primary-key }} - name: Build libraries, tests and examples - run: xmake -vD -j 3 + run: xmake - name: Upload dependency failure logs if: ${{ failure() }} diff --git a/README.md b/README.md index 5035850b..fc1deed2 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,8 @@ The repository provides engine libraries, built-in renderers, asset authoring to The default build includes enabled libraries and tests. Benchmark targets join it with `--benchmarks=y`. +CI imports platform settings from `.github/configs/windows-clang.conf`, `windows-msvc.conf`, or `macos-arm64.conf`, then runs `xmake` with its default verbosity and parallelism. For example: `xmake f -y --import=.github/configs/macos-arm64.conf`. Put Homebrew LLVM on `PATH` before using the macOS configuration. + | Option | Default | Description | | --- | --- | --- | | `--profile=y` | `n` | Enable [Tracy](https://github.com/wolfpld/tracy) profiling | From 7cf8c383adddd3d3aac04acb56b6922cbecb13d9 Mon Sep 17 00:00:00 2001 From: L-Sun Date: Sat, 24 Oct 2026 19:32:07 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=F0=9F=90=9B=20[test]=20avoid=20PocketJS=20?= =?UTF-8?q?namespace=20alias=20collision=20with=20MSVC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hitagi/engine/gui/test/draw_contract_test.cpp | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/hitagi/engine/gui/test/draw_contract_test.cpp b/hitagi/engine/gui/test/draw_contract_test.cpp index f0a1ff6d..c7ae46b3 100644 --- a/hitagi/engine/gui/test/draw_contract_test.cpp +++ b/hitagi/engine/gui/test/draw_contract_test.cpp @@ -3,31 +3,31 @@ import interop.gtest; import interop.pocketjs; import std; -namespace pocket = hitagi::interop::pocketjs; +namespace pocketjs = hitagi::interop::pocketjs; -static_assert(std::is_same_v); -static_assert(sizeof(pocket::PixelFormat) == sizeof(std::uint32_t)); -static_assert(alignof(pocket::PixelFormat) == alignof(std::uint32_t)); +static_assert(std::is_same_v); +static_assert(sizeof(pocketjs::PixelFormat) == sizeof(std::uint32_t)); +static_assert(alignof(pocketjs::PixelFormat) == alignof(std::uint32_t)); TEST(PocketDrawContractTest, RejectsUnknownAndTruncatedCommands) { - EXPECT_EQ(pocket::CommandWordCount(nullptr, 0), 0u); + EXPECT_EQ(pocketjs::CommandWordCount(nullptr, 0), 0u); const std::array unknown = {0xffffffff}; - EXPECT_EQ(pocket::CommandWordCount(unknown.data(), 1), 0u); - const std::array rect = {std::to_underlying(pocket::DrawOp::Rect), 0, 0, 0}; - EXPECT_EQ(pocket::CommandWordCount(rect.data(), 3), 0u); - EXPECT_EQ(pocket::CommandWordCount(rect.data(), 4), 4u); + EXPECT_EQ(pocketjs::CommandWordCount(unknown.data(), 1), 0u); + const std::array rect = {std::to_underlying(pocketjs::DrawOp::Rect), 0, 0, 0}; + EXPECT_EQ(pocketjs::CommandWordCount(rect.data(), 3), 0u); + EXPECT_EQ(pocketjs::CommandWordCount(rect.data(), 4), 4u); } TEST(PocketDrawContractTest, ValidatesGlyphAndPaddedTextPayloads) { - const std::array glyphs = {std::to_underlying(pocket::DrawOp::GlyphRun), 2u << 16, 0, 0, 0, 0, 0}; - EXPECT_EQ(pocket::CommandWordCount(glyphs.data(), 1), 0u); - EXPECT_EQ(pocket::CommandWordCount(glyphs.data(), 6), 0u); - EXPECT_EQ(pocket::CommandWordCount(glyphs.data(), 7), 7u); - std::array text = {std::to_underlying(pocket::DrawOp::TextRun), 0, 0, 0, 0, 0, 0, 5, 0, 0}; - EXPECT_EQ(pocket::CommandWordCount(text.data(), 9), 0u); - EXPECT_EQ(pocket::CommandWordCount(text.data(), 10), 10u); + const std::array glyphs = {std::to_underlying(pocketjs::DrawOp::GlyphRun), 2u << 16, 0, 0, 0, 0, 0}; + EXPECT_EQ(pocketjs::CommandWordCount(glyphs.data(), 1), 0u); + EXPECT_EQ(pocketjs::CommandWordCount(glyphs.data(), 6), 0u); + EXPECT_EQ(pocketjs::CommandWordCount(glyphs.data(), 7), 7u); + std::array text = {std::to_underlying(pocketjs::DrawOp::TextRun), 0, 0, 0, 0, 0, 0, 5, 0, 0}; + EXPECT_EQ(pocketjs::CommandWordCount(text.data(), 9), 0u); + EXPECT_EQ(pocketjs::CommandWordCount(text.data(), 10), 10u); text[7] = 4; - EXPECT_EQ(pocket::CommandWordCount(text.data(), 9), 9u); + EXPECT_EQ(pocketjs::CommandWordCount(text.data(), 9), 9u); text[7] = 0xffffffff; - EXPECT_EQ(pocket::CommandWordCount(text.data(), 10), 0u); + EXPECT_EQ(pocketjs::CommandWordCount(text.data(), 10), 0u); } From 95f85cd14f46a3fdbfd816784912483da2ee8a0f Mon Sep 17 00:00:00 2001 From: L-Sun Date: Sat, 24 Oct 2026 20:20:47 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=F0=9F=90=9B=20[test]=20move=20backend=20co?= =?UTF-8?q?nditionals=20outside=20GoogleTest=20macros?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hitagi/engine/render/test/deferred_test.cpp | 11 +++++------ hitagi/engine/render/test/pbr_test.cpp | 6 +++--- hitagi/engine/render/test/skinning_test.cpp | 6 +++--- hitagi/engine/render/test/toon_test.cpp | 6 +++--- hitagi/engine/render/test/window_test.cpp | 6 +++--- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/hitagi/engine/render/test/deferred_test.cpp b/hitagi/engine/render/test/deferred_test.cpp index 75fec694..53ad98ad 100644 --- a/hitagi/engine/render/test/deferred_test.cpp +++ b/hitagi/engine/render/test/deferred_test.cpp @@ -21,14 +21,13 @@ using namespace hitagi::render::deferred; class DeferredRendererTest : public TestWithParam {}; -INSTANTIATE_TEST_SUITE_P(Backends, DeferredRendererTest, Values( #ifdef _WIN32 - gfx::Device::Type::DX12, +INSTANTIATE_TEST_SUITE_P(Backends, DeferredRendererTest, Values(gfx::Device::Type::DX12, gfx::Device::Type::Vulkan)); +#elif defined(__APPLE__) +INSTANTIATE_TEST_SUITE_P(Backends, DeferredRendererTest, Values(gfx::Device::Type::Metal, gfx::Device::Type::Vulkan)); +#else +INSTANTIATE_TEST_SUITE_P(Backends, DeferredRendererTest, Values(gfx::Device::Type::Vulkan)); #endif -#ifdef __APPLE__ - gfx::Device::Type::Metal, -#endif - gfx::Device::Type::Vulkan)); class DeferredExtensionProbe final : public IDeferredRenderExtension { public: diff --git a/hitagi/engine/render/test/pbr_test.cpp b/hitagi/engine/render/test/pbr_test.cpp index b1c1ef92..b9b68953 100644 --- a/hitagi/engine/render/test/pbr_test.cpp +++ b/hitagi/engine/render/test/pbr_test.cpp @@ -26,11 +26,11 @@ class FrameProducer final : public core::RuntimeModule { class PbrRendererTest : public testing::TestWithParam {}; -INSTANTIATE_TEST_SUITE_P(Backends, PbrRendererTest, testing::Values( #ifdef _WIN32 - gfx::Device::Type::DX12, +INSTANTIATE_TEST_SUITE_P(Backends, PbrRendererTest, testing::Values(gfx::Device::Type::DX12, gfx::Device::Type::Vulkan)); +#else +INSTANTIATE_TEST_SUITE_P(Backends, PbrRendererTest, testing::Values(gfx::Device::Type::Vulkan)); #endif - gfx::Device::Type::Vulkan)); TEST_P(PbrRendererTest, EmptyFrameClearsApplicationTargetAcrossExecutions) { auto device = gfx::create_device(GetParam()); diff --git a/hitagi/engine/render/test/skinning_test.cpp b/hitagi/engine/render/test/skinning_test.cpp index 75c6d666..fc9aee81 100644 --- a/hitagi/engine/render/test/skinning_test.cpp +++ b/hitagi/engine/render/test/skinning_test.cpp @@ -112,11 +112,11 @@ auto Triangle(bool deferred, bool toon = false) -> std::shared_ptr } // namespace skinning_render_test class SkinningRendererTest : public testing::TestWithParam {}; -INSTANTIATE_TEST_SUITE_P(Backends, SkinningRendererTest, testing::Values( #ifdef _WIN32 - gfx::Device::Type::DX12, +INSTANTIATE_TEST_SUITE_P(Backends, SkinningRendererTest, testing::Values(gfx::Device::Type::DX12, gfx::Device::Type::Vulkan)); +#else +INSTANTIATE_TEST_SUITE_P(Backends, SkinningRendererTest, testing::Values(gfx::Device::Type::Vulkan)); #endif - gfx::Device::Type::Vulkan)); TEST_P(SkinningRendererTest, AllRenderersKeepSharedMeshInstanceStreamsAndSubmittedSnapshots) { core::JobSystem jobs; diff --git a/hitagi/engine/render/test/toon_test.cpp b/hitagi/engine/render/test/toon_test.cpp index 6b6afd35..7def1d3a 100644 --- a/hitagi/engine/render/test/toon_test.cpp +++ b/hitagi/engine/render/test/toon_test.cpp @@ -93,11 +93,11 @@ auto Sphere(std::shared_ptr material) -> std::shared_ptr {}; -INSTANTIATE_TEST_SUITE_P(Backends, ToonRendererTest, testing::Values( #ifdef _WIN32 - gfx::Device::Type::DX12, +INSTANTIATE_TEST_SUITE_P(Backends, ToonRendererTest, testing::Values(gfx::Device::Type::DX12, gfx::Device::Type::Vulkan)); +#else +INSTANTIATE_TEST_SUITE_P(Backends, ToonRendererTest, testing::Values(gfx::Device::Type::Vulkan)); #endif - gfx::Device::Type::Vulkan)); TEST_P(ToonRendererTest, ThreeBandsAndSupersamplingPreserveDepthForLaterPasses) { auto device = gfx::create_device(GetParam()); diff --git a/hitagi/engine/render/test/window_test.cpp b/hitagi/engine/render/test/window_test.cpp index e91710b5..23e3e040 100644 --- a/hitagi/engine/render/test/window_test.cpp +++ b/hitagi/engine/render/test/window_test.cpp @@ -115,11 +115,11 @@ void ExerciseWindow(Application& app, gfx::CommandQueues& queues, std::unique_pt } class WindowRendererTest : public testing::TestWithParam {}; -INSTANTIATE_TEST_SUITE_P(Backends, WindowRendererTest, testing::Values( #ifdef _WIN32 - gfx::Device::Type::DX12, +INSTANTIATE_TEST_SUITE_P(Backends, WindowRendererTest, testing::Values(gfx::Device::Type::DX12, gfx::Device::Type::Vulkan)); +#else +INSTANTIATE_TEST_SUITE_P(Backends, WindowRendererTest, testing::Values(gfx::Device::Type::Vulkan)); #endif - gfx::Device::Type::Vulkan)); TEST_P(WindowRendererTest, PbrOwnsPresentationAndRetainsFrameAcrossResize) { auto app = Application::CreateApp({.width = 320, .height = 240, .headless = true}); From a51f485d2aae0e44a74a7ad894132d37898972e7 Mon Sep 17 00:00:00 2001 From: L-Sun Date: Sat, 24 Oct 2026 20:27:18 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=F0=9F=90=9B=20[physics]=20avoid=20duplicat?= =?UTF-8?q?e=20defaulted=20destructor=20symbols=20in=20MSVC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hitagi/engine/physics/physics.cpp | 4 +++- hitagi/engine/physics/rig.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/hitagi/engine/physics/physics.cpp b/hitagi/engine/physics/physics.cpp index d6d79f15..5fcecda9 100644 --- a/hitagi/engine/physics/physics.cpp +++ b/hitagi/engine/physics/physics.cpp @@ -589,7 +589,9 @@ JoltRigWorld::JoltRigWorld(std::span bodies, std::span poses) { auto& d = *m_Impl; if (poses.size() != d.bodies.size()) throw std::invalid_argument("Rig pose count mismatch"); diff --git a/hitagi/engine/physics/rig.cpp b/hitagi/engine/physics/rig.cpp index f5271f2c..05a72eba 100644 --- a/hitagi/engine/physics/rig.cpp +++ b/hitagi/engine/physics/rig.cpp @@ -124,7 +124,9 @@ RigWorld::RigWorld(std::span bodies, std::span jo } } -RigWorld::~RigWorld() = default; +// Keep an explicit body: MSVC emits duplicate symbols for the defaulted +// out-of-line destructor when this module is imported by rig tests. +RigWorld::~RigWorld() {} void RigWorld::Reset(std::span poses) { if (m_Jolt) return m_Jolt->Reset(poses);