Skip to content
Open
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
120 changes: 120 additions & 0 deletions .claude/skills/bridge-build/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
---
name: bridge-build
description: Build the Remix Bridge (32-bit client d3d9 + 64-bit server NvRemixBridge) via the bridge/build.ps1 wrapper. Use when the user asks to build, compile, compile-check, smoke-test, or force a clean rebuild of the bridge specifically — the bridge is a separate component from the main runtime and has its own build flow. Reports exit code + verifies artifacts. Do NOT invoke for runtime-side edits (src/) — those are rtx-build's domain.
---

# bridge-build

Wraps [`bridge/build.ps1`](../../../bridge/build.ps1). The script
discovers Visual Studio via vswhere, calls vcvarsall.bat by full path
(avoiding the `bridge/build_common.ps1::SetupVS` silent-failure trap),
runs `meson setup`/`compile` per arch in isolated cmd.exe shells (no env
contamination between x64 and x86), and verifies all three expected
artifacts before reporting success.

The bridge is the IPC layer that lets a 32-bit game talk to the 64-bit
Remix runtime. Client and server live under `bridge/` and build into
*separate* meson dirs (one per arch).

## When to invoke

- User asks to build, compile, compile-check, or smoke-test the bridge
- After a code change that touches `bridge/src/client/`,
`bridge/src/server/`, `bridge/src/util/`, `bridge/src/launcher/`,
or any IPC opcode/struct shared between client and server
- After a `public/include/remix/remix_c.h` change that affects the
Remix C API surface (the bridge consumes that header)
- Before pushing changes that touch the bridge

## When NOT to invoke

- Edits only under `src/` or other runtime-side code — that's
`rtx-build`'s domain
- Doc-only changes (`bridge/README.md`, `.md`, etc.)
- Skill / settings / config edits
- When the user asks for the main runtime build — invoke `rtx-build`
instead

## Steps

1. From the project root, kick off the build with
`run_in_background: true` (expected duration: ~30s incremental,
2-4 min cold full for both arches):

```powershell
& .\bridge\build.ps1
```

For non-default flavor: `-Flavor debug` or `-Flavor debugoptimized`.
For single-arch: `-Arch x64` or `-Arch x86`. Add `-Clean` to wipe
the matching `_comp*` dir(s) first.

2. Wait for the task-completion notification — DO NOT poll, the
runtime will wake you up when the background command exits.

3. Report back:
- **Green (exit 0):** the script's own output ends with
`=== Bridge build OK ===` and prints all three artifacts
(x64 server, x86 client, x86 launcher) with mtimes. Quote those
lines.
- **Mixed-date warning:** if x64 server and x86 client mtimes are
from different commits, flag this — IPC ABI risk if the command
opcodes/structs in `bridge/src/util/` shifted between commits.
- **Red (non-zero exit):** scan the captured output for
`error C[0-9]`, `FAILED:`, `ninja: build stopped`. Quote the
first ~10 error lines verbatim.

## Flavors

| Flavor | `--buildtype` | Build dirs |
|---|---|---|
| release (default) | `release` | `_compRelease_x64`, `_compRelease_x86` |
| debug | `debug` | `_compDebug_x64`, `_compDebug_x86` |
| debugoptimized | `debugoptimized` | `_compDebugOptimized_x64`, `_compDebugOptimized_x86` |

## Output layout

After a successful build, deployable binaries live in `bridge/_output/`:

```
bridge/_output/
├── d3d9.dll ← x86 client (canonical name; deploy AS-IS)
├── NvRemixLauncher32.exe ← x86 injection launcher
├── d3d9.lib, d3d9.exp ← link artifacts (not needed at runtime)
└── .trex/
└── NvRemixBridge.exe ← x64 server
```

> **PDBs may go stale.** The `copy_d3d9_to_output` custom_target globs
> `d3d9*` but in practice the linker may emit the .pdb after the copy
> step has already run, leaving stale debug symbols in `_output/`. If
> you need fresh symbols (crash analysis, dump inspection), copy
> `_compRelease_x86/src/client/d3d9.pdb` to `_output/d3d9.pdb`
> manually after the build.

## Gotchas

- **Don't bypass the script** by calling `build_bridge_release.bat`
(or `_debug.bat`, `_all.bat`, etc.) directly. Under any subprocess
context where the parent shell hasn't already loaded VS env, the
.bat's `SetupVS`/vcvarsall lookup silently fails, the .bat exits 0
with no x86 build output, and the .bat's empty captured stdout
(`cmd.exe /c` stdio quirk) hides the failure. `bridge/build.ps1`
was written specifically to fix that trap.
- **Two separate build dirs.** Unlike rtx-build (single dir), the
bridge has `_compRelease_x64` (server only) and `_compRelease_x86`
(client + launcher). Ninja runs against each independently — one
side can rebuild while the other is a no-op when sources match.
- **MSVC v142 toolchain required.** Either VS2019 directly, or
VS2022 with the v142 toolset Individual Component installed.
The script's vswhere call uses `-version '[16.0,18.0)'` so either
works.
- **`gametargets.conf` deploy path.** If the user has set up
`bridge/gametargets.conf`, meson auto-deploys binaries into the
configured game dirs as part of the build. The bridge's
`gametargets.conf` output dir should be the *parent* of the
`.trex/` folder (unlike the main runtime's gametargets, which
points AT `.trex/`).
- **Bridge can run standalone** (without the main `dxvk-remix`
runtime). In that case it falls back to system d3d9.dll — no
pathtracing, but useful for IPC smoke tests.
80 changes: 80 additions & 0 deletions .claude/skills/rtx-build/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
name: rtx-build
description: Build the dxvk-remix runtime (64-bit d3d9.dll) via the repo-root build.ps1 wrapper. Use when the user asks to build, compile, compile-check, verify, or smoke-test the runtime. Runs in the background, reports exit code + verifies artifacts. Do NOT invoke for doc/skill/config-only edits — those don't affect compilation.
---

# rtx-build

Wraps [`build.ps1`](../../../build.ps1) at the repo root. The script
discovers Visual Studio via vswhere, calls vcvarsall.bat by full path
(avoiding the `build_common.ps1::SetupVS` silent-failure trap), runs
`meson setup`/`compile`/`install` in a single isolated cmd.exe shell,
and verifies build artifacts exist before reporting success.

## When to invoke

- User asks to build, compile, compile-check, verify, or smoke-test
- Before pushing code changes
- After a code change that touches runtime sources under `src/`,
`include/`, or `public/`

## When NOT to invoke

- Doc-only changes (`.md`, `documentation/`, `.claude/`) — no
compile impact
- Skill / settings / config edits
- Bridge-only changes — invoke `bridge-build` instead
- Before the user has finished their code edits — building against a
work-in-progress tree wastes time

## Steps

1. From the project root, kick off the build with
`run_in_background: true` (expected duration: ~30s incremental,
10-15 min cold full):

```powershell
& .\build.ps1
```

For non-default flavor, add `-Flavor debug` or
`-Flavor debugoptimized`. Add `-Clean` to wipe the build dir
first. Add `-EnableTracy` to enable the Tracy profiler.

2. Wait for the task-completion notification — DO NOT poll, the
runtime will wake you up when the background command exits.

3. Report back:
- **Green (exit 0):** the script's own output ends with
`=== Runtime build OK ===` and prints the artifact paths +
mtimes. Quote those lines.
- **Red (non-zero exit):** scan the captured output for
`error C[0-9]`, `fatal error`, `FAILED:`, `ninja: build stopped`,
or `Failed to run`. Quote the first ~10 error lines so the user
sees the real cause before any fix attempt.

## Flavors

| Flavor | `--buildtype` | Build dir |
|---|---|---|
| release (default) | `release` | `_Comp64Release` |
| debug | `debug` | `_Comp64Debug` |
| debugoptimized | `debugoptimized` | `_Comp64DebugOptimized` |

## Gotchas

- **`LNK4098: defaultlib 'LIBCMT' conflicts`** is a pre-existing
warning, not a failure.
- **`WARNING: msvc does not support C++11; attempting best effort`**
is upstream noise, not a failure.
- **Build produces `d3d9.dll`** in `_Comp64Release/src/d3d9/` and
installs it to `_output/`, `public/bin/`, and the test app dirs.
- **Don't bypass the script** by calling `build_common.ps1::PerformBuild`
directly. It works, but its `SetupVS` function lies about success
when vcvarsall.bat lookup fails — invisible until the next
consumer hits a stale build. `build.ps1` is the audited entry
point that doesn't have that trap.
- **Optional auto-deploy:** drop an `auto-deploy.local.ps1` at the
repo root (gitignored) that sets `$AutoDeployTargets = @('C:\path\to\game\.trex')`.
The build will copy `_output/d3d9.dll` to each listed path after a
successful build.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ metrics.txt
nrc_session_log.txt
python.dxvk-cache
*.xml.user
/auto-deploy.local.ps1
139 changes: 139 additions & 0 deletions bridge/build.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#requires -version 5.1
<#
.SYNOPSIS
Build the Remix Bridge (32-bit client + 64-bit server) reliably.

.DESCRIPTION
PowerShell wrapper around the meson/ninja bridge build. Discovers
Visual Studio via vswhere, calls vcvarsall.bat by full path, and runs
meson setup + compile per arch in isolated cmd.exe shells (no env
contamination between x64 and x86). Streams output to the PowerShell
pipeline so progress and errors are visible. Throws on any non-zero
exit and verifies the expected build artifacts exist before reporting
success.

Resolves the failure mode in bridge/build_common.ps1::SetupVS where a
missing C++ workload silently no-ops: cmd writes "'vcvarsall.bat' is
not recognized" to stderr, the piped `set` dumps the existing env,
the ForEach loop re-sets the same vars, and the script proceeds with
no VC env loaded. Under build_bridge_release.bat the failure further
hides because the .bat captures cmd's empty stdout and exits 0 with
no client output.
Comment on lines +7 to +21

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason the existing build scripts can't be upgraded with these advantages, rather than introducing a new wrapper around them?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They very well can be if that's preferred! I wasn't sure if the original build scripts should be touched or not due to internal workflows or other similar things.


.PARAMETER Flavor
release (default), debug, debugoptimized.

.PARAMETER Arch
x64, x86, or both (default).

.PARAMETER Clean
Wipe the matching _comp* dir(s) before building.

.EXAMPLE
.\bridge\build.ps1
.\bridge\build.ps1 -Arch x86 -Clean
.\bridge\build.ps1 -Flavor debugoptimized -Arch both
#>
[CmdletBinding()]
param(
[ValidateSet('release','debug','debugoptimized')]
[string]$Flavor = 'release',

[ValidateSet('x64','x86','both')]
[string]$Arch = 'both',

[switch]$Clean
)

$ErrorActionPreference = 'Stop'

$BridgeRoot = $PSScriptRoot
$flavorTag = switch ($Flavor) {
'release' { 'Release' }
'debug' { 'Debug' }
'debugoptimized' { 'DebugOptimized' }
}
$buildDirPrefix = "_comp$flavorTag"

# --- Discover Visual Studio ---
$vsWhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe'
if (-not (Test-Path $vsWhere)) {
throw "vswhere.exe not found at '$vsWhere'. Install the Visual Studio Installer (ships with VS2017+)."
}
$vsPath = & $vsWhere -latest -version '[16.0,18.0)' -property installationPath
if ([string]::IsNullOrWhiteSpace($vsPath)) {
throw "No Visual Studio 2019 or 2022 installation with v142 toolchain found via vswhere."
}
$vcvars = Join-Path $vsPath 'VC\Auxiliary\Build\vcvarsall.bat'
if (-not (Test-Path $vcvars)) {
throw "vcvarsall.bat not found at '$vcvars'. The detected VS install may be incomplete (missing C++ build tools workload)."
}

Write-Host "VS install: $vsPath" -ForegroundColor DarkGray
Write-Host "vcvars: $vcvars" -ForegroundColor DarkGray
Write-Host "Bridge root: $BridgeRoot" -ForegroundColor DarkGray
Write-Host "Flavor: $Flavor / $Arch" -ForegroundColor DarkGray

$arches = if ($Arch -eq 'both') { @('x64','x86') } else { @($Arch) }

Set-Location $BridgeRoot

foreach ($a in $arches) {
$buildDir = "${buildDirPrefix}_$a"
Write-Host ""
Write-Host "=== Bridge $a $Flavor -> $buildDir ===" -ForegroundColor Cyan

if ($Clean -and (Test-Path $buildDir)) {
Write-Host "Wiping $buildDir for clean rebuild..." -ForegroundColor Yellow
Remove-Item -Path $buildDir -Recurse -Force
}

$alreadyConfigured = Test-Path (Join-Path $buildDir 'meson-private')
if ($alreadyConfigured) {
# meson auto-reconfigures from inside the build dir if meson.build changed
$chain = "call `"$vcvars`" $a >nul 2>&1 && cd $buildDir && meson compile"
} else {
$chain = "call `"$vcvars`" $a >nul 2>&1 && meson setup --buildtype $Flavor --backend ninja $buildDir && cd $buildDir && meson compile"
}

# Native-command stderr triggers PowerShell's NativeCommandError under
# EAP=Stop even on exit 0. Exit code is the authoritative signal here.
$prevEAP = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
try {
cmd.exe /c $chain
$exit = $LASTEXITCODE
} finally {
$ErrorActionPreference = $prevEAP
}
if ($exit -ne 0) {
throw "Bridge $a $Flavor build failed (exit $exit)."
}
}

# Sanity-check artifacts so the caller can trust exit 0
$expected = @{}
if ($arches -contains 'x64') {
$expected["${buildDirPrefix}_x64/src/server/NvRemixBridge.exe"] = 'x64 server'
}
if ($arches -contains 'x86') {
$expected["${buildDirPrefix}_x86/src/client/d3d9.dll"] = 'x86 client'
$expected["${buildDirPrefix}_x86/src/launcher/NvRemixLauncher32.exe"] = 'x86 launcher'
}

$missing = @()
foreach ($rel in $expected.Keys) {
$abs = Join-Path $BridgeRoot $rel
if (-not (Test-Path $abs)) { $missing += "$($expected[$rel]) ($rel)" }
}
if ($missing.Count -gt 0) {
throw "Build reported success but artifacts are missing: $($missing -join ', ')"
}

Write-Host ""
Write-Host "=== Bridge build OK ===" -ForegroundColor Green
foreach ($rel in $expected.Keys) {
$abs = Join-Path $BridgeRoot $rel
$info = Get-Item $abs
Write-Host (" {0,-14} {1:yyyy-MM-dd HH:mm} {2,10:N0} bytes {3}" -f $expected[$rel], $info.LastWriteTime, $info.Length, $rel) -ForegroundColor Green
}
Loading