# Building and Running Xenia Canary Windows Debug from Linux

## What we built and why

A Windows-MSVC debug `xenia_canary.exe` cross-compiled on Linux, runnable under Wine. This serves as the audit oracle for the xenia-rs Rust port: the Linux-native canary build stalls before the front-end UI, so all audit comparisons (memory entries audit_044–audit_059) need the Wine-targeted debug binary as the ground-truth reference engine.

## Phase 1 — Host setup (run in your terminal)

    sudo apt install -y clang-18 lld-18 llvm-18      # clang-cl driver mode + lld-link + binutils
    sudo ln -s /usr/bin/clang-18 /usr/bin/clang-cl   # activates MSVC-compatible driver mode
    xwin --accept-license --arch x86_64 splat --include-debug-libs --output ~/.xwin/splat
                                                      # ~807 MB Win10 SDK + MSVC CRT sysroot
    curl ... linkid=2361406 -o ~/winsdk.iso          # Win10 SDK ISO for real fxc.exe (SM 5_1)
    winetricks -q vkd3d                              # vkd3d-proton d3d12core.dll (5.96 MB)
    winetricks -q dxvk                               # DXVK dxgi.dll (2.95 MB)

Ubuntu's clang-18 / lld-18 apt packages ship binutils suffixed (llvm-lib-18, lld-link-18, etc.); the toolchain expects unsuffixed names on PATH. Create 4 symlinks in `~/.local/bin/` (no sudo needed since it was already on PATH).

## Phase 2 — In-tree edits

### 8 build-fix patches (compile-time only; zero runtime semantics changes)

| § | File | What changed |
|---|---|---|
| 7.1 | `src/xenia/base/mapped_memory_win.cc:30` | `constexpr` → `const` for `kFileHandleInvalid` (clang-cl rejects `reinterpret_cast` in constant expressions) |
| 7.2 | `src/xenia/app/main_resources.rc:3` | `..\\..\\..\\assets\\icon\\icon.ico` → forward slashes (llvm-rc backslash literalism) |
| 7.3 | `third_party/snappy/snappy-stubs-public.h` | Already in place via the `fabi/sylpheed-crossbuild` snappy fork submodule |
| 7.4 | `third_party/zlib-ng/zconf-ng.h:113` | `#if 1` → `#if !defined(_WIN32)` for `Z_HAVE_UNISTD_H` (header was pre-generated on Linux) |
| 7.5 | `third_party/CMakeLists.txt:335` | Extended `if(NOT MSVC)` → `if(NOT MSVC OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")` for zlib-ng AVX flags |
| 7.6a | `CMakeLists.txt` | Wrapped `/RTCsu` appends in `CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC" AND NOT … "Clang"` |
| 7.6b | `CMakeLists.txt:85-101` | Inserted `execute_process` block invoking `xenia-build.py:generate_version_h()` so CMake-direct flow produces `version.h` |
| 7.7 | `cmake/XeniaHelpers.cmake` | Added `_env_prefix` to wrap per-shader commands in `cmake -E env FXC_PATH=…` (`cmake set(ENV{…})` doesn't survive ninja's subprocess spawn) |
| 7.8 | `tools/build/compile_shader_dxbc.py:74` | Added `_wineify()` helper translating unix paths via `winepath -w` before fxc sees them (fxc parses `/home/…` as a `/h` switch) |

### 3 new cross-compile config files

| File | Purpose |
|---|---|
| `cmake/toolchains/linux-to-win-msvc.cmake` | clang-cl + lld-link + xwin sysroot driver. Forces `MultiThreadedDLL` runtime (no debug-CRT DLLs needed), feeds `-imsvc` flags via `SHELL:` prefix, suppresses 15+ clang-cl-specific warnings, defines `_mm_cvtsi64x_si128` alias, opts out of MSVC STL's Clang≥19 assertion, plumbs `FXC_PATH` |
| `cmake/toolchains/xwin-case-symlinks.py` | Scans xenia includes for mixed-case Windows headers and creates the missing case-aliases in xwin's flat splat (5 needed: `ObjBase.h`, `Psapi.h`, etc.) |
| `CMakePresets.json` | Added `cross-win-clangcl` configure preset + `cross-debug` / `cross-release` / `cross-checked` build presets, gated on `${hostSystemName}` ≠ Windows |

## Phase 3 — Configure + build

    python3 cmake/toolchains/xwin-case-symlinks.py "$PWD" "$HOME/.xwin/splat"
    # Created 5 case-symlinks across 556 unique includes

    cmake --preset cross-win-clangcl
    # Generates build-cross/ with build-Debug.ninja + auto-generated version.h

    cmake --build build-cross --preset cross-debug --target xenia-app -j6
    # 936 ninja targets. -j6 not -j12 because host RAM is tight (~3.4 GiB free at start)
    # Wall time ~25 min total

Final output: `xenia_canary.exe` (27 MB PE32+ GUI x86-64) + `xenia_canary.pdb` (116 MB CodeView).

## Phase 4 — Running the game

    cd "/home/fabi/RE Project Sylpheed/xenia-canary/build-cross/bin/Windows/Debug"
    WINEDEBUG=-all wine ./xenia_canary.exe --mute=true \
        "/home/fabi/RE Project Sylpheed/Project Sylpheed - Arc of Deception (USA, Europe) (En,Ja).iso"

Kill after the boot phase completes (the audit workflow only needs ~30 s of trajectory):

    sleep 30
    wineserver -k

### Expected boot signals in `xenia.log`

| Signal | Value | Meaning |
|---|---|---|
| Total log lines | 1091 | Healthy boot (≥1000 = passes) |
| `^x>` fatals | 0 | No `xe::FatalError()` triggered |
| `^!>` errors | 28 | Non-fatal (occasional pipeline misses — normal) |
| `^w>` warnings | 28 | Normal startup |
| `i> Setup: Initializing chain` | Memory → Exports → Processor → Audio → Graphics → HID → VFS → Kernel | All eight subsystems came up |
| `i> Setup: Starting graphics_system + Starting audio_system` | present | Threads spawned cleanly |
| DXGI adapter | NVIDIA GeForce GTX 1070 Ti | vkd3d-proton + DXVK loaded |
| `K> XThread::Execute thid N count` | 29 | Guest threads spawned (game is past `XexLoadImage`) |
| `Skipping draw - pipeline not ready: VS … PS …` repeating | yes | D3D12 backend is async-compiling pipelines — expected on cold boot |
| `F>` channel | 321 lines | VFS is mounting and walking the disc image |
| `K>` channel | 29 lines | Kernel dispatching XThread creation |

## Audit-workflow integration

The cross-build is now the sole canary oracle. The Linux-native `xenia-canary/build/bin/Linux/Debug/xenia_canary` is deprecated for audits.

All canary launches must include `--mute=true` (project policy 2026-05-12). XAudio2 still initializes — same code paths, silent output. Do not substitute `--apu=nop`; that switches backend entirely.

Point logs at `audit-runs` with `--log_file=`:

    LOG="$XENIA_RS_ROOT/xenia-rs/audit-runs/audit_NN/canary.log" \
    WINEDEBUG=-all wine xenia_canary.exe \
        --mute=true --log_file="$LOG" \
        --audit_NN_my_probe=true \
        "$ISO_PATH"

Add new audit instrumentation as cvars in `cpu_flags.h` / `gpu_flags.h` / `kernel_flags.h`, guard with `if (cvars::audit_NN_my_probe)`, emit `XELOGI("AUDIT-NN-EVENT …")`. Rebuild incrementally — only the touched TU recompiles, ≤60 s.

The build is observation-only: cvars + `XELOG*()` + `#if`-gated diagnostic blocks are permitted; changing control flow, return values, struct layouts, or timing is forbidden, since that would invalidate every downstream audit comparison.
