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>
293 lines
9.5 KiB
CMake
293 lines
9.5 KiB
CMake
# XeniaHelpers.cmake - Helper functions for the Xenia build system.
|
|
# Replaces tools/build/scripts/*.lua
|
|
|
|
include(CMakeParseArguments)
|
|
|
|
# Platform suffix lists for file filtering
|
|
set(XE_PLATFORM_SUFFIXES
|
|
_win _linux _posix _gnulinux _x11 _gtk _android _mac _amd64 _x64 _arm64
|
|
)
|
|
|
|
# xe_platform_sources(target base_path [RECURSIVE])
|
|
#
|
|
# Adds platform-filtered source files to a target.
|
|
# Globs *.h, *.cc, *.cpp, *.c, *.inc from base_path.
|
|
# Excludes all platform suffixes, then adds back the ones matching the current platform.
|
|
# Always excludes *_main.cc and *_test.cc.
|
|
function(xe_platform_sources target base_path)
|
|
set(options RECURSIVE)
|
|
cmake_parse_arguments(ARG "${options}" "" "" ${ARGN})
|
|
|
|
if(ARG_RECURSIVE)
|
|
set(glob_mode GLOB_RECURSE)
|
|
set(pattern "**")
|
|
else()
|
|
set(glob_mode GLOB)
|
|
set(pattern "*")
|
|
endif()
|
|
|
|
# Glob all source files
|
|
file(${glob_mode} _all_sources "${base_path}/*.h"
|
|
"${base_path}/*.cc"
|
|
"${base_path}/*.cpp"
|
|
"${base_path}/*.c"
|
|
"${base_path}/*.inc"
|
|
)
|
|
|
|
# Build exclude patterns
|
|
set(_excluded)
|
|
foreach(src ${_all_sources})
|
|
get_filename_component(_name_we ${src} NAME_WE)
|
|
# Exclude *_main.cc, *_test.cc, and *_demo.cc
|
|
if(_name_we MATCHES "_main$" OR _name_we MATCHES "_test$" OR _name_we MATCHES "_demo$")
|
|
list(APPEND _excluded ${src})
|
|
continue()
|
|
endif()
|
|
# Exclude all platform suffixes
|
|
foreach(suffix ${XE_PLATFORM_SUFFIXES})
|
|
if(_name_we MATCHES "${suffix}$")
|
|
list(APPEND _excluded ${src})
|
|
break()
|
|
endif()
|
|
endforeach()
|
|
endforeach()
|
|
|
|
# Remove excluded files
|
|
set(_sources ${_all_sources})
|
|
if(_excluded)
|
|
list(REMOVE_ITEM _sources ${_excluded})
|
|
endif()
|
|
|
|
# Add back platform-specific files
|
|
if(WIN32)
|
|
file(${glob_mode} _plat_sources "${base_path}/*_win.h"
|
|
"${base_path}/*_win.cc"
|
|
)
|
|
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
|
file(${glob_mode} _plat_sources "${base_path}/*_posix.h"
|
|
"${base_path}/*_posix.cc"
|
|
"${base_path}/*_linux.h"
|
|
"${base_path}/*_linux.cc"
|
|
"${base_path}/*_gnulinux.h"
|
|
"${base_path}/*_gnulinux.cc"
|
|
"${base_path}/*_x11.h"
|
|
"${base_path}/*_x11.cc"
|
|
"${base_path}/*_gtk.h"
|
|
"${base_path}/*_gtk.cc"
|
|
)
|
|
endif()
|
|
|
|
list(APPEND _sources ${_plat_sources})
|
|
|
|
# Add back architecture-specific files
|
|
if(XE_TARGET_X86_64)
|
|
file(${glob_mode} _arch_sources "${base_path}/*_amd64.h" "${base_path}/*_amd64.cc"
|
|
"${base_path}/*_x64.h" "${base_path}/*_x64.cc")
|
|
elseif(XE_TARGET_AARCH64)
|
|
file(${glob_mode} _arch_sources "${base_path}/*_arm64.h" "${base_path}/*_arm64.cc")
|
|
endif()
|
|
if(_arch_sources)
|
|
list(APPEND _sources ${_arch_sources})
|
|
endif()
|
|
|
|
target_sources(${target} PRIVATE ${_sources})
|
|
endfunction()
|
|
|
|
# xe_target_defaults(target)
|
|
#
|
|
# Applies xenia-specific compile settings to a target:
|
|
# - Fatal warnings (-Werror / /WX)
|
|
# - Common include directories
|
|
function(xe_target_defaults target)
|
|
target_include_directories(${target} PRIVATE
|
|
${PROJECT_SOURCE_DIR}
|
|
${PROJECT_SOURCE_DIR}/src
|
|
${PROJECT_SOURCE_DIR}/third_party
|
|
)
|
|
if(MSVC)
|
|
target_compile_options(${target} PRIVATE /WX)
|
|
# Recreate directory structure in Visual Studio filters
|
|
get_target_property(_srcs ${target} SOURCES)
|
|
if(_srcs)
|
|
set(_local_srcs)
|
|
set(_external_srcs)
|
|
foreach(_s IN LISTS _srcs)
|
|
get_filename_component(_abs "${_s}" ABSOLUTE)
|
|
string(FIND "${_abs}" "${CMAKE_CURRENT_SOURCE_DIR}" _pos)
|
|
if(_pos EQUAL 0)
|
|
list(APPEND _local_srcs "${_s}")
|
|
else()
|
|
list(APPEND _external_srcs "${_s}")
|
|
endif()
|
|
endforeach()
|
|
if(_local_srcs)
|
|
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${_local_srcs})
|
|
endif()
|
|
if(_external_srcs)
|
|
source_group(TREE ${PROJECT_SOURCE_DIR} PREFIX "External" FILES ${_external_srcs})
|
|
endif()
|
|
endif()
|
|
elseif(NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
# GCC is too noisy for -Werror; only apply to Clang
|
|
target_compile_options(${target} PRIVATE -Werror)
|
|
endif()
|
|
endfunction()
|
|
|
|
# xe_shader_rules_spirv(target shader_dir)
|
|
#
|
|
# Ensures SPIR-V shaders are compiled before the target builds.
|
|
# Uses a stamp file; rebuilds when any shader source changes.
|
|
function(xe_shader_rules_spirv target shader_dir)
|
|
get_filename_component(shader_dir "${shader_dir}" ABSOLUTE)
|
|
file(GLOB _sources
|
|
"${shader_dir}/*.xesl" "${shader_dir}/*.glsl"
|
|
"${shader_dir}/*.xesli" "${shader_dir}/*.glsli")
|
|
set(_stamp "${CMAKE_CURRENT_BINARY_DIR}/${target}_spirv.stamp")
|
|
set(_script "${PROJECT_SOURCE_DIR}/tools/build/compile_shader_spirv.py")
|
|
set(_valid_stages vs hs ds gs ps cs)
|
|
set(_commands)
|
|
set(_bytecode_dir "${shader_dir}/bytecode/vulkan_spirv")
|
|
list(APPEND _commands COMMAND ${CMAKE_COMMAND} -E make_directory "${_bytecode_dir}")
|
|
foreach(src ${_sources})
|
|
get_filename_component(_name ${src} NAME)
|
|
string(REGEX REPLACE "\\.[^.]+$" "" _basename "${_name}")
|
|
string(REPLACE "." "_" _id "${_basename}")
|
|
string(LENGTH "${_id}" _len)
|
|
if(_len LESS 3)
|
|
continue()
|
|
endif()
|
|
math(EXPR _s "${_len} - 2")
|
|
string(SUBSTRING "${_id}" ${_s} 2 _stage)
|
|
if(NOT _stage IN_LIST _valid_stages)
|
|
continue()
|
|
endif()
|
|
list(APPEND _commands COMMAND ${Python3_EXECUTABLE} "${_script}" "${src}" "${_bytecode_dir}/${_id}.h")
|
|
endforeach()
|
|
add_custom_command(
|
|
OUTPUT "${_stamp}"
|
|
${_commands}
|
|
COMMAND ${CMAKE_COMMAND} -E touch "${_stamp}"
|
|
DEPENDS ${_sources} "${_script}"
|
|
COMMENT "Compiling SPIR-V shaders for ${target}..."
|
|
VERBATIM
|
|
)
|
|
add_custom_target(${target}-spirv-shaders DEPENDS "${_stamp}")
|
|
add_dependencies(${target} ${target}-spirv-shaders)
|
|
# Add sources for IDE visibility but prevent VS from compiling them itself
|
|
set_source_files_properties(${_sources} PROPERTIES HEADER_FILE_ONLY TRUE)
|
|
target_sources(${target} PRIVATE ${_sources})
|
|
endfunction()
|
|
|
|
# xe_shader_rules_dxbc(target shader_dir)
|
|
#
|
|
# Ensures DXBC shaders are compiled before the target builds.
|
|
# Uses a stamp file; rebuilds when any shader source changes.
|
|
function(xe_shader_rules_dxbc target shader_dir)
|
|
get_filename_component(shader_dir "${shader_dir}" ABSOLUTE)
|
|
file(GLOB _sources
|
|
"${shader_dir}/*.xesl" "${shader_dir}/*.hlsl"
|
|
"${shader_dir}/*.xesli" "${shader_dir}/*.hlsli")
|
|
set(_stamp "${CMAKE_CURRENT_BINARY_DIR}/${target}_dxbc.stamp")
|
|
set(_script "${PROJECT_SOURCE_DIR}/tools/build/compile_shader_dxbc.py")
|
|
set(_valid_stages vs hs ds gs ps cs)
|
|
set(_commands)
|
|
set(_bytecode_dir "${shader_dir}/bytecode/d3d12_5_1")
|
|
# Propagate FXC_PATH from the configure-time env so ninja-spawned python
|
|
# subprocesses can find fxc.exe (CMake `set(ENV{...})` doesn't reach build).
|
|
set(_env_prefix "")
|
|
if(DEFINED ENV{FXC_PATH})
|
|
set(_env_prefix ${CMAKE_COMMAND} -E env "FXC_PATH=$ENV{FXC_PATH}")
|
|
endif()
|
|
list(APPEND _commands COMMAND ${CMAKE_COMMAND} -E make_directory "${_bytecode_dir}")
|
|
foreach(src ${_sources})
|
|
get_filename_component(_name ${src} NAME)
|
|
string(REGEX REPLACE "\\.[^.]+$" "" _basename "${_name}")
|
|
string(REPLACE "." "_" _id "${_basename}")
|
|
string(LENGTH "${_id}" _len)
|
|
if(_len LESS 3)
|
|
continue()
|
|
endif()
|
|
math(EXPR _s "${_len} - 2")
|
|
string(SUBSTRING "${_id}" ${_s} 2 _stage)
|
|
if(NOT _stage IN_LIST _valid_stages)
|
|
continue()
|
|
endif()
|
|
list(APPEND _commands COMMAND ${_env_prefix} ${Python3_EXECUTABLE} "${_script}" "${src}" "${_bytecode_dir}/${_id}.h")
|
|
endforeach()
|
|
add_custom_command(
|
|
OUTPUT "${_stamp}"
|
|
${_commands}
|
|
COMMAND ${CMAKE_COMMAND} -E touch "${_stamp}"
|
|
DEPENDS ${_sources} "${_script}"
|
|
COMMENT "Compiling DXBC shaders for ${target}..."
|
|
VERBATIM
|
|
)
|
|
add_custom_target(${target}-dxbc-shaders DEPENDS "${_stamp}")
|
|
add_dependencies(${target} ${target}-dxbc-shaders)
|
|
# Add sources for IDE visibility but prevent VS from compiling them itself
|
|
set_source_files_properties(${_sources} PROPERTIES HEADER_FILE_ONLY TRUE)
|
|
target_sources(${target} PRIVATE ${_sources})
|
|
endfunction()
|
|
|
|
# xe_force_c(files...)
|
|
#
|
|
# Forces the given source files to compile as C.
|
|
function(xe_force_c)
|
|
set_source_files_properties(${ARGN} PROPERTIES LANGUAGE C)
|
|
endfunction()
|
|
|
|
# xe_force_cxx(files...)
|
|
#
|
|
# Forces the given source files to compile as C++.
|
|
function(xe_force_cxx)
|
|
set_source_files_properties(${ARGN} PROPERTIES LANGUAGE CXX)
|
|
endfunction()
|
|
|
|
# xe_test_suite(name base_path LINKS lib1 lib2 ...)
|
|
#
|
|
# Creates a Catch2 test executable from *_test.cc files in base_path.
|
|
function(xe_test_suite name base_path)
|
|
cmake_parse_arguments(ARG "" "" "LINKS" ${ARGN})
|
|
|
|
file(GLOB _test_sources "${base_path}/*_test.cc")
|
|
|
|
if(NOT _test_sources)
|
|
return()
|
|
endif()
|
|
|
|
add_executable(${name}
|
|
${_test_sources}
|
|
${PROJECT_SOURCE_DIR}/tools/build/src/test_suite_main.cc
|
|
)
|
|
|
|
# Add platform-specific console app main
|
|
if(WIN32)
|
|
target_sources(${name} PRIVATE
|
|
${PROJECT_SOURCE_DIR}/src/xenia/base/console_app_main_win.cc)
|
|
else()
|
|
target_sources(${name} PRIVATE
|
|
${PROJECT_SOURCE_DIR}/src/xenia/base/console_app_main_posix.cc)
|
|
endif()
|
|
|
|
target_compile_definitions(${name} PRIVATE
|
|
"XE_TEST_SUITE_NAME=\"${name}\""
|
|
)
|
|
target_include_directories(${name} PRIVATE
|
|
${PROJECT_SOURCE_DIR}/tools/build
|
|
${PROJECT_SOURCE_DIR}/tools/build/src
|
|
${PROJECT_SOURCE_DIR}/tools/build/third_party/catch/include
|
|
)
|
|
if(ARG_LINKS)
|
|
target_link_libraries(${name} PRIVATE ${ARG_LINKS})
|
|
endif()
|
|
xe_target_defaults(${name})
|
|
set_target_properties(${name} PROPERTIES FOLDER "tests")
|
|
|
|
if(MSVC)
|
|
# Disable Edit and Continue - breaks Catch2 __LINE__ usage
|
|
target_compile_options(${name} PRIVATE /Zi)
|
|
endif()
|
|
|
|
catch_discover_tests(${name})
|
|
endfunction()
|