Files
Xenia-Canary/CMakeLists.txt
MechaCat02 2233fae235 [Build] Guard ThinLTO behind XENIA_ENABLE_LTO for memory-constrained hosts
Release enables -flto=thin unconditionally; the ThinLTO link spikes memory
past what a 15GB box can handle. Gate it behind an option (default ON, so
normal/CI builds are unchanged); pass -DXENIA_ENABLE_LTO=OFF to build
Release without the LTO memory spike.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 15:43:23 +02:00

356 lines
13 KiB
CMake

cmake_minimum_required(VERSION 3.20)
if(APPLE)
project(xenia LANGUAGES C CXX OBJCXX)
set(CMAKE_OBJCXX_STANDARD 20)
set(CMAKE_OBJCXX_STANDARD_REQUIRED ON)
else()
project(xenia LANGUAGES C CXX)
endif()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_C_STANDARD 17)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Detect target architecture.
# - VS generator: CMAKE_GENERATOR_PLATFORM (from -A flag) takes priority.
# - Ninja/Makefiles: CMAKE_SYSTEM_PROCESSOR (set via -DCMAKE_SYSTEM_NAME
# + -DCMAKE_SYSTEM_PROCESSOR for cross-compile, or auto-detected natively).
if(CMAKE_GENERATOR_PLATFORM)
if(CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64")
set(XE_TARGET_AARCH64 TRUE)
set(XE_TARGET_X86_64 FALSE)
else()
set(XE_TARGET_AARCH64 FALSE)
set(XE_TARGET_X86_64 TRUE)
endif()
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64|arm64")
set(XE_TARGET_AARCH64 TRUE)
set(XE_TARGET_X86_64 FALSE)
else()
set(XE_TARGET_AARCH64 FALSE)
set(XE_TARGET_X86_64 TRUE)
endif()
message(STATUS "Target architecture: XE_TARGET_AARCH64=${XE_TARGET_AARCH64} XE_TARGET_X86_64=${XE_TARGET_X86_64} (CMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR})")
# Options
option(XENIA_BUILD_TESTS "Build test suites" OFF)
option(XENIA_BUILD_MISC "Build misc subprojects (trace viewers, shader compiler, vfs-dump, demos)" OFF)
# Toggle profiler
add_compile_definitions(XE_OPTION_PROFILING=0)
add_compile_definitions(XE_OPTION_PROFILING_UI=0)
if(XENIA_BUILD_TESTS)
enable_testing()
include(${PROJECT_SOURCE_DIR}/third_party/catch/contrib/Catch.cmake)
endif()
# Multi-config generators (VS, Ninja Multi-Config)
get_property(_is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(_is_multi_config)
set(CMAKE_CONFIGURATION_TYPES "Checked;Debug;Release" CACHE STRING "" FORCE)
endif()
# Custom Checked configuration (ASan + debug runtime)
set(CMAKE_C_FLAGS_CHECKED "${CMAKE_C_FLAGS_DEBUG}" CACHE STRING "" FORCE)
set(CMAKE_CXX_FLAGS_CHECKED "${CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING "" FORCE)
set(CMAKE_EXE_LINKER_FLAGS_CHECKED "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" CACHE STRING "" FORCE)
set(CMAKE_SHARED_LINKER_FLAGS_CHECKED "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE STRING "" FORCE)
set(CMAKE_STATIC_LINKER_FLAGS_CHECKED "${CMAKE_STATIC_LINKER_FLAGS_DEBUG}" CACHE STRING "" FORCE)
# Platform name for output paths
if(WIN32)
set(XE_PLATFORM_NAME "Windows")
elseif(APPLE)
set(XE_PLATFORM_NAME "macOS")
else()
set(XE_PLATFORM_NAME "Linux")
endif()
# Output directories — strip any vs-* nesting from CMAKE_BINARY_DIR so that
# VS and Ninja builds for the same architecture share an output directory,
# while different architectures (build/ vs build-arm64/) stay separate.
string(REGEX REPLACE "/vs-[^/]+$" "" XE_OUTPUT_ROOT "${CMAKE_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${XE_OUTPUT_ROOT}/bin/${XE_PLATFORM_NAME}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${XE_OUTPUT_ROOT}/bin/${XE_PLATFORM_NAME}")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/obj/${XE_PLATFORM_NAME}")
# Create scratch/ if needed
file(MAKE_DIRECTORY "${PROJECT_SOURCE_DIR}/scratch")
# Python for shader compilation scripts
find_package(Python3 REQUIRED COMPONENTS Interpreter)
# Generate build-tree version.h via xenia-build.py's generate_version_h()
# (normally invoked by `xb premake`/`xb build`; CMake-direct flows need it too).
execute_process(
COMMAND ${Python3_EXECUTABLE} -c
"import importlib.util,sys; \
spec=importlib.util.spec_from_file_location('xb',r'${PROJECT_SOURCE_DIR}/xenia-build.py'); \
m=importlib.util.module_from_spec(spec); spec.loader.exec_module(m); \
m.generate_version_h(r'${CMAKE_BINARY_DIR}')"
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
RESULT_VARIABLE _xenia_version_rc
)
if(NOT _xenia_version_rc EQUAL 0)
message(WARNING "version.h generation failed (rc=${_xenia_version_rc}); writing stub.")
file(WRITE "${CMAKE_BINARY_DIR}/version.h"
"#ifndef GENERATED_VERSION_H_\n#define GENERATED_VERSION_H_\n#define XE_BUILD_BRANCH \"unknown\"\n#define XE_BUILD_COMMIT \"unknown\"\n#define XE_BUILD_COMMIT_SHORT \"unknown\"\n#define XE_BUILD_DATE __DATE__\n#endif\n")
endif()
# Include helpers
include(cmake/XeniaHelpers.cmake)
# Global include directories (these apply to all targets via directory scope)
include_directories(
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}
)
# Third-party headers as SYSTEM to suppress warnings under -Werror
include_directories(SYSTEM
${PROJECT_SOURCE_DIR}/third_party
)
# Global defines
add_compile_definitions(
VULKAN_HPP_NO_TO_STRING
IMGUI_DISABLE_DEFAULT_FONT
USE_CPP17 # Tabulate
)
# Prevent ASan error from ImGUI
add_compile_definitions($<$<NOT:$<CONFIG:Checked>>:IMGUI_USE_STB_SPRINTF>)
# Static library define
add_compile_definitions(_LIB)
# ==============================================================================
# Platform-specific global settings
# ==============================================================================
if(MSVC)
# Global MSVC settings
add_compile_options(
/utf-8 # Build correctly on systems with non-Latin codepages
/wd4201 # Nameless struct/unions are ok
/MP # Multi-processor compilation
)
if(XE_TARGET_X86_64)
add_compile_options(/arch:AVX)
endif()
add_compile_definitions(
_CRT_NONSTDC_NO_DEPRECATE
_CRT_SECURE_NO_WARNINGS
WIN32
_WIN64=1
_AMD64=1
UNICODE
_UNICODE
IMGUI_DISABLE_OBSOLETE_FUNCTIONS
)
add_link_options(
/ignore:4006 # Ignores complaints about empty obj files
/ignore:4221
)
# Global Windows system libraries
link_libraries(
ntdll wsock32 ws2_32 xinput comctl32 shcore shlwapi dxguid bcrypt
)
# Windows manifest for executables is handled per-target
# --- Per-configuration MSVC flags ---
# Checked
if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC"
AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
string(APPEND CMAKE_C_FLAGS_CHECKED " /RTCsu /fsanitize=address")
string(APPEND CMAKE_CXX_FLAGS_CHECKED " /RTCsu /fsanitize=address")
else()
string(APPEND CMAKE_C_FLAGS_CHECKED " /fsanitize=address")
string(APPEND CMAKE_CXX_FLAGS_CHECKED " /fsanitize=address")
endif()
string(APPEND CMAKE_EXE_LINKER_FLAGS_CHECKED " /INCREMENTAL:NO")
add_compile_definitions($<$<CONFIG:Checked>:DEBUG>)
# Debug: use release runtime (/MD) for heap performance, matching premake
string(REPLACE "/MDd" "/MD" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
string(REPLACE "/MDd" "/MD" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
add_compile_definitions($<$<CONFIG:Debug>:DEBUG>)
add_compile_definitions($<$<CONFIG:Debug>:_NO_DEBUG_HEAP=1>)
# Checked or Debug: full symbols
string(APPEND CMAKE_C_FLAGS_CHECKED " /Zi")
string(APPEND CMAKE_CXX_FLAGS_CHECKED " /Zi")
# Debug already has /Zi by default
# Release
add_compile_definitions($<$<CONFIG:Release>:NDEBUG>)
add_compile_definitions($<$<CONFIG:Release>:_NO_DEBUG_HEAP=1>)
add_compile_options($<$<CONFIG:Release>:/Gw>)
add_compile_options($<$<CONFIG:Release>:/GS->) # NoBufferSecurityCheck
add_compile_options($<$<CONFIG:Release>:/Zi>) # Generate PDB debug info
add_link_options($<$<CONFIG:Release>:/DEBUG>) # Emit .pdb for the linked binary
add_link_options($<$<CONFIG:Release>:/OPT:REF>) # Remove unreferenced functions/data
add_link_options($<$<CONFIG:Release>:/OPT:ICF>) # Fold identical COMDATs
# Replace /Ob2 with /Ob3 in CMake's default Release flags
string(REPLACE "/Ob2" "/Ob3" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
string(REPLACE "/Ob2" "/Ob3" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
# Link-time optimization (whole program optimization)
add_compile_options($<$<CONFIG:Release>:/GL>)
add_link_options($<$<CONFIG:Release>:/LTCG>)
set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG")
else()
# GCC/Clang (Linux)
if(XE_TARGET_X86_64)
add_compile_options(-mavx)
endif()
# Disable specific warnings for C++
add_compile_options(
$<$<COMPILE_LANGUAGE:CXX>:-Wno-switch>
$<$<COMPILE_LANGUAGE:CXX>:-Wno-attributes>
)
# Clang-specific C++ warnings
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(
$<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-register>
$<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-volatile>
$<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-enum-enum-conversion>
)
# Check Clang version for newer warnings
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 20)
add_compile_options(
$<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-literal-operator>
$<$<COMPILE_LANGUAGE:CXX>:-Wno-nontrivial-memcall>
)
endif()
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 21)
add_compile_options(
$<$<COMPILE_LANGUAGE:CXX>:-Wno-character-conversion>
)
endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# GCC-specific
add_compile_options(
$<$<COMPILE_LANGUAGE:CXX>:-Wno-unused-result>
$<$<COMPILE_LANGUAGE:CXX>:-Wno-volatile>
$<$<COMPILE_LANGUAGE:CXX>:-Wno-template-id-cdtor>
$<$<COMPILE_LANGUAGE:CXX>:-Wno-return-type>
$<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated>
-fpermissive # HACK
)
add_link_options(-fpermissive)
# GCC: do not use -Werror
endif()
# C-specific warnings
add_compile_options(
$<$<COMPILE_LANGUAGE:C>:-Wno-implicit-function-declaration>
$<$<COMPILE_LANGUAGE:C>:-Wno-incompatible-pointer-types>
)
if(APPLE)
# macOS-specific settings
set(CMAKE_OSX_DEPLOYMENT_TARGET "15.0" CACHE STRING "Minimum macOS version")
add_compile_options(
$<$<COMPILE_LANGUAGE:CXX>:-Wno-shorten-64-to-32>
-Wno-deprecated-declarations
-Wno-character-conversion
)
add_link_options(-Wl,-no_warn_duplicate_libraries)
link_libraries(
"-framework CoreFoundation"
"-framework Foundation"
"-framework IOKit"
dl
pthread
)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
# GTK3 via pkg-config
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK3 REQUIRED gtk+-x11-3.0)
include_directories(${GTK3_INCLUDE_DIRS})
link_directories(${GTK3_LIBRARY_DIRS})
add_compile_options(${GTK3_CFLAGS_OTHER})
# Global Linux libraries
link_libraries(stdc++fs dl lz4 pthread rt)
# Link groups for executables (resolves circular deps)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--start-group")
set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -Wl,--end-group")
endif()
# --- Per-configuration flags ---
# Checked
string(APPEND CMAKE_C_FLAGS_CHECKED " -fsanitize=address")
string(APPEND CMAKE_CXX_FLAGS_CHECKED " -fsanitize=address")
string(APPEND CMAKE_EXE_LINKER_FLAGS_CHECKED " -fsanitize=address")
add_compile_definitions(
$<$<CONFIG:Checked>:DEBUG>
)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_compile_definitions($<$<CONFIG:Checked>:_GLIBCXX_DEBUG>)
endif()
# Debug
add_compile_definitions(
$<$<CONFIG:Debug>:DEBUG>
$<$<CONFIG:Debug>:_NO_DEBUG_HEAP=1>
)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_compile_definitions($<$<CONFIG:Debug>:_GLIBCXX_DEBUG>)
endif()
# Release
add_compile_definitions(
$<$<CONFIG:Release>:NDEBUG>
$<$<CONFIG:Release>:_NO_DEBUG_HEAP=1>
)
add_compile_options($<$<CONFIG:Release>:-O3>)
# Link-time optimization (use lld and llvm-ar/ranlib to avoid system
# linker/archiver LTO plugin version mismatch with clang's bitcode).
# Guarded so memory-constrained hosts can build Release without the
# ThinLTO link-time memory spike: pass -DXENIA_ENABLE_LTO=OFF.
option(XENIA_ENABLE_LTO "Enable ThinLTO for Release builds" ON)
if(XENIA_ENABLE_LTO)
add_compile_options($<$<CONFIG:Release>:-flto=thin>)
add_link_options($<$<CONFIG:Release>:-flto=thin>)
endif()
add_link_options($<$<CONFIG:Release>:-fuse-ld=lld>)
find_program(LLVM_AR NAMES llvm-ar)
find_program(LLVM_RANLIB NAMES llvm-ranlib)
if(LLVM_AR)
set(CMAKE_AR "${LLVM_AR}" CACHE FILEPATH "" FORCE)
endif()
if(LLVM_RANLIB)
set(CMAKE_RANLIB "${LLVM_RANLIB}" CACHE FILEPATH "" FORCE)
endif()
# No symbols in release on non-Windows
string(REPLACE "-g" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
string(REPLACE "-g" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
endif()
# ==============================================================================
# Subdirectories
# ==============================================================================
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# Third-party libraries first (no -Werror applied to these)
set(CMAKE_FOLDER "third_party")
add_subdirectory(third_party)
# Xenia source modules (xe_target_defaults applies -Werror)
set(CMAKE_FOLDER "src")
add_subdirectory(src/xenia)
set(CMAKE_FOLDER "")
# Set default startup project for Visual Studio
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT xenia-app)