snapshot: preserve the uncommitted Canary instrumentation (not authored here)
Some checks failed
Orchestrator / Commit Message Validation (push) Has been skipped
Orchestrator / Lint (push) Failing after 2m0s
Orchestrator / Windows (x86-64) (push) Has been skipped
Orchestrator / Linux (x86-64) (push) Has been skipped
Orchestrator / Create Release (push) Has been skipped
Some checks failed
Orchestrator / Commit Message Validation (push) Has been skipped
Orchestrator / Lint (push) Failing after 2m0s
Orchestrator / Windows (x86-64) (push) Has been skipped
Orchestrator / Linux (x86-64) (push) Has been skipped
Orchestrator / Create Release (push) Has been skipped
Working-tree snapshot taken 2026-07-28 so this work is not lost. To be clear about provenance: NONE of this was written in the session that committed it — it is pre-existing uncommitted work on phase-a-tracing, last committed 2026-07-09, from the xenia-rs decoder/deadlock investigation. It is recorded verbatim, not reviewed and not tested. Contents: 24 tracked modifications (ppc_emit_memory, xex_module, object_table, shim_utils, xboxkrnl threading/rtl, xevent/xobject/xthread, memory) plus the untracked probe sources audit_68_host_mem_watch, audit_69_event_signal_watch, audit_70_semaphore_release_watch, phase_b_snapshot, and cmake/toolchains. Deliberately excluded: build-cross/ (51 GB of build output) and vkd3d-proton.cache. Note third_party/snappy is a submodule pointer change whose target may not be pushed anywhere, so this branch is a preservation record rather than a guaranteed-buildable tree. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
119
cmake/toolchains/linux-to-win-msvc.cmake
Normal file
119
cmake/toolchains/linux-to-win-msvc.cmake
Normal file
@@ -0,0 +1,119 @@
|
||||
# Linux host -> Windows MSVC-ABI cross toolchain using clang-cl + lld-link
|
||||
# + xwin-supplied Win10 SDK/CRT. Driven by Ninja Multi-Config.
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||
|
||||
if(NOT DEFINED XWIN_DIR)
|
||||
if(DEFINED ENV{XWIN_DIR})
|
||||
set(XWIN_DIR "$ENV{XWIN_DIR}")
|
||||
else()
|
||||
set(XWIN_DIR "$ENV{HOME}/.xwin/splat")
|
||||
endif()
|
||||
endif()
|
||||
set(XWIN_DIR "${XWIN_DIR}" CACHE PATH "xwin splat root (contains crt/ and sdk/)")
|
||||
|
||||
if(NOT EXISTS "${XWIN_DIR}/crt/include")
|
||||
message(FATAL_ERROR "XWIN_DIR=${XWIN_DIR} missing crt/include - run xwin splat.")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_COMPILER clang-cl)
|
||||
set(CMAKE_CXX_COMPILER clang-cl)
|
||||
set(CMAKE_LINKER lld-link)
|
||||
set(CMAKE_RC_COMPILER llvm-rc)
|
||||
set(CMAKE_AR llvm-lib)
|
||||
set(CMAKE_MT llvm-mt)
|
||||
|
||||
set(CMAKE_C_COMPILER_TARGET x86_64-pc-windows-msvc)
|
||||
set(CMAKE_CXX_COMPILER_TARGET x86_64-pc-windows-msvc)
|
||||
|
||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||
|
||||
# Force /MD (release CRT) for every config. xenia's CMakeLists.txt does a
|
||||
# `string(REPLACE "/MDd" "/MD" ...)` on CMAKE_CXX_FLAGS_DEBUG, but with
|
||||
# clang-cl, the runtime selection comes from CMAKE_MSVC_RUNTIME_LIBRARY
|
||||
# (which expands to -MDd in dash form), so the substitution misses.
|
||||
# Pinning the policy here avoids the need for non-redistributable debug
|
||||
# CRT DLLs (MSVCP140D.dll etc) at runtime, which xwin doesn't ship.
|
||||
cmake_policy(SET CMP0091 NEW)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
|
||||
|
||||
# xwin's default splat is a flat layout (crt/include, sdk/include/{ucrt,um,shared,...}),
|
||||
# which clang-cl's /winsysroot does NOT understand. Use explicit -imsvc + -libpath:
|
||||
# instead. Re-running `xwin splat --use-winsysroot-style` would also work but
|
||||
# requires re-downloading ~600 MB.
|
||||
# Use SHELL: prefix so CMake doesn't deduplicate repeated -imsvc tokens.
|
||||
add_compile_options(
|
||||
"SHELL:-imsvc \"${XWIN_DIR}/crt/include\""
|
||||
"SHELL:-imsvc \"${XWIN_DIR}/sdk/include/ucrt\""
|
||||
"SHELL:-imsvc \"${XWIN_DIR}/sdk/include/um\""
|
||||
"SHELL:-imsvc \"${XWIN_DIR}/sdk/include/shared\""
|
||||
"SHELL:-imsvc \"${XWIN_DIR}/sdk/include/winrt\""
|
||||
)
|
||||
add_link_options(
|
||||
"/libpath:${XWIN_DIR}/crt/lib/x86_64"
|
||||
"/libpath:${XWIN_DIR}/sdk/lib/ucrt/x86_64"
|
||||
"/libpath:${XWIN_DIR}/sdk/lib/um/x86_64"
|
||||
)
|
||||
# xwin pulls the latest MSVC STL which now hard-asserts Clang >= 19. Our host
|
||||
# has Clang 18, which works fine in practice — opt out of the version check.
|
||||
# (See yvals_core.h STL1000 in $XWIN_DIR/crt/include.)
|
||||
add_compile_definitions(_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH)
|
||||
# llvm-rc needs SDK headers explicitly + the resource file's own dir so the
|
||||
# RC's relative ICON path (..\..\..\assets\icon\icon.ico) resolves.
|
||||
get_filename_component(_toolchain_dir "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
|
||||
get_filename_component(_xenia_root "${_toolchain_dir}/../.." ABSOLUTE)
|
||||
set(CMAKE_RC_FLAGS_INIT
|
||||
"/I \"${XWIN_DIR}/sdk/include/um\" /I \"${XWIN_DIR}/sdk/include/shared\" /I \"${_xenia_root}/src/xenia/app\"")
|
||||
|
||||
# Quiet MSVC-STL false positives and xenia-specific warnings that clang-cl
|
||||
# emits but cl.exe doesn't (treated as errors under /WX).
|
||||
add_compile_options(
|
||||
-Wno-microsoft-include
|
||||
-Wno-unused-command-line-argument
|
||||
-Wno-ignored-pragma-intrinsic
|
||||
-Wno-nonportable-include-path
|
||||
-Wno-pragma-pack
|
||||
-Wno-tautological-pointer-compare
|
||||
-Wno-microsoft-cast
|
||||
-Wno-deprecated-declarations
|
||||
# These are silenced for native Linux Clang in CMakeLists.txt's else() branch,
|
||||
# but the if(MSVC) branch fires under clang-cl and skips them — so re-add.
|
||||
-Wno-switch
|
||||
-Wno-attributes
|
||||
-Wno-deprecated-register
|
||||
-Wno-deprecated-volatile
|
||||
-Wno-deprecated-enum-enum-conversion
|
||||
# cl.exe accepts __pragma(optimize("s",on)); clang-cl only knows the empty
|
||||
# argument form. xenia gates XE_MSVC_OPTIMIZE_SMALL on _MSC_VER so the
|
||||
# rejected pragma still emits from the clang-cl path. Treat as no-op.
|
||||
-Wno-ignored-pragmas
|
||||
# xenia decorates several `virtual` methods with XE_FORCEINLINE; clang-cl
|
||||
# then complains that the inline body isn't visible in includer TUs
|
||||
# (definitions live in command_processor.cc). cl.exe accepts this silently.
|
||||
-Wno-undefined-inline
|
||||
-Wno-sizeof-pointer-memaccess
|
||||
# `'ZM'` (PE magic, stored little-endian as "MZ" in the binary) — cl.exe
|
||||
# accepts the multi-char constant silently; clang-cl errors under /WX.
|
||||
-Wno-multichar
|
||||
)
|
||||
# _mm_cvtsi64x_si128 is an MSVC-only alias for the standard _mm_cvtsi64_si128.
|
||||
# Used (gated on XE_PLATFORM_WIN32) in xenia/gpu/draw_util.cc.
|
||||
add_compile_definitions(_mm_cvtsi64x_si128=_mm_cvtsi64_si128)
|
||||
|
||||
# Plumb FXC for tools/build/compile_shader_dxbc.py (wine fxc auto-prepend).
|
||||
# Use real Win10 SDK fxc.exe 10.x (supports SM 5_1, produces vkd3d-proton-
|
||||
# acceptable DXBC). Extracted from the Win11 SDK 26100 ISO -> Store Apps
|
||||
# Tools MSI's CABs.
|
||||
if(DEFINED ENV{FXC_PATH})
|
||||
set(ENV_FXC "$ENV{FXC_PATH}")
|
||||
else()
|
||||
set(ENV_FXC "$ENV{HOME}/.local/share/xenia-cross/fxc/fxc.exe")
|
||||
endif()
|
||||
set(ENV{FXC_PATH} "${ENV_FXC}")
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH "${XWIN_DIR}")
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
126
cmake/toolchains/xwin-case-symlinks.py
Normal file
126
cmake/toolchains/xwin-case-symlinks.py
Normal file
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Scan xenia source for #include directives and ensure case-aliases exist
|
||||
in xwin's flat SDK/CRT include dirs. xwin's default splat adds lowercase
|
||||
aliases for headers that ship with uppercase names (e.g. Windows.h),
|
||||
but does NOT add aliases in the reverse direction. xenia (and its
|
||||
third_party deps) include some headers using historical Microsoft casing
|
||||
(<ObjBase.h>, <Psapi.h>) that don't match the lowercase filenames the
|
||||
SDK ships with. This helper creates the missing symlinks.
|
||||
|
||||
Idempotent: re-running is safe.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
INCLUDE_RE = re.compile(r'^\s*#\s*include\s*<([A-Za-z][A-Za-z0-9_/.\-]*\.h)>',
|
||||
re.MULTILINE)
|
||||
|
||||
SOURCE_ROOTS = [
|
||||
"src",
|
||||
"third_party/SDL2/src",
|
||||
"third_party/SDL2/include",
|
||||
"third_party/discord-rpc/src",
|
||||
"third_party/fmt",
|
||||
"third_party/imgui",
|
||||
]
|
||||
|
||||
SOURCE_EXTS = {".h", ".hpp", ".inc", ".c", ".cc", ".cpp", ".cxx"}
|
||||
|
||||
|
||||
def collect_includes(repo_root: Path) -> set[str]:
|
||||
"""Return set of all <foo.h>-style include targets found in source."""
|
||||
seen: set[str] = set()
|
||||
for root in SOURCE_ROOTS:
|
||||
base = repo_root / root
|
||||
if not base.exists():
|
||||
continue
|
||||
for path in base.rglob("*"):
|
||||
if path.suffix.lower() not in SOURCE_EXTS:
|
||||
continue
|
||||
try:
|
||||
txt = path.read_text(encoding="utf-8", errors="ignore")
|
||||
except OSError:
|
||||
continue
|
||||
for m in INCLUDE_RE.finditer(txt):
|
||||
seen.add(m.group(1))
|
||||
return seen
|
||||
|
||||
|
||||
def index_dir(d: Path) -> dict[str, str]:
|
||||
"""Return mapping lowercased-basename -> actual basename for files in d."""
|
||||
if not d.is_dir():
|
||||
return {}
|
||||
idx: dict[str, str] = {}
|
||||
for entry in d.iterdir():
|
||||
idx.setdefault(entry.name.lower(), entry.name)
|
||||
return idx
|
||||
|
||||
|
||||
def fix_dir(target_dir: Path, want: set[str]) -> tuple[int, int, list[str]]:
|
||||
"""For each header name in `want` (basename only), create a symlink to
|
||||
the case-folded sibling if the exact case doesn't exist. Returns
|
||||
(created, already_ok, missing-from-sdk)."""
|
||||
if not target_dir.is_dir():
|
||||
return 0, 0, []
|
||||
idx = index_dir(target_dir)
|
||||
created = 0
|
||||
already_ok = 0
|
||||
missing: list[str] = []
|
||||
for name in want:
|
||||
# Only look at single-segment names; subdir/foo.h handled separately
|
||||
if "/" in name:
|
||||
continue
|
||||
actual = idx.get(name.lower())
|
||||
if actual is None:
|
||||
missing.append(name)
|
||||
continue
|
||||
if actual == name:
|
||||
already_ok += 1
|
||||
continue
|
||||
link = target_dir / name
|
||||
if link.exists() or link.is_symlink():
|
||||
already_ok += 1
|
||||
continue
|
||||
try:
|
||||
link.symlink_to(actual)
|
||||
created += 1
|
||||
except OSError as e:
|
||||
print(f" ! failed to symlink {link} -> {actual}: {e}",
|
||||
file=sys.stderr)
|
||||
return created, already_ok, missing
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if len(sys.argv) != 3:
|
||||
print("usage: xwin-case-symlinks.py <xenia-canary-root> <xwin-splat-dir>",
|
||||
file=sys.stderr)
|
||||
return 2
|
||||
repo_root = Path(sys.argv[1]).resolve()
|
||||
xwin_root = Path(sys.argv[2]).resolve()
|
||||
if not (xwin_root / "crt" / "include").exists():
|
||||
print(f"error: {xwin_root}/crt/include missing", file=sys.stderr)
|
||||
return 1
|
||||
want = collect_includes(repo_root)
|
||||
print(f"Collected {len(want)} unique #include <...> targets")
|
||||
sdk_dirs = [
|
||||
xwin_root / "crt" / "include",
|
||||
xwin_root / "sdk" / "include" / "ucrt",
|
||||
xwin_root / "sdk" / "include" / "um",
|
||||
xwin_root / "sdk" / "include" / "shared",
|
||||
xwin_root / "sdk" / "include" / "winrt",
|
||||
]
|
||||
total_created = 0
|
||||
for d in sdk_dirs:
|
||||
created, ok, _missing = fix_dir(d, want)
|
||||
if created:
|
||||
print(f" {d}: created {created} case-symlinks")
|
||||
total_created += created
|
||||
print(f"Done: created {total_created} case-symlinks total")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user