# 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.