[Build] Linux→Windows cross-compile toolchain (clang-cl + xwin)
New CMake preset `cross-win-clangcl` for Ninja Multi-Config on non-Windows hosts. Toolchain: clang-cl (MSVC-ABI), lld-link, xwin SDK/CRT splat. Shader compilation routes through wine fxc.exe with FXC_PATH env forwarding and unix→Windows path translation via `winepath -w`. Plus per-file build fixes (constexpr→const, llvm-rc forward-slash, zlib-ng AVX guard, /RTCsu MSVC-only). third_party/snappy bumped to fabi/sylpheed-crossbuild for the target-aware POSIX-gate header. Produces `xenia_canary.exe` (Debug MSVC) suitable for use as the audit oracle under Wine for xenia-rs work. See docs/CROSS_BUILD_SETUP.md for the full reproduction recipe. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
100
docs/CROSS_BUILD_SETUP.md
Normal file
100
docs/CROSS_BUILD_SETUP.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user