Repository navigation
Expand file tree
/
Copy pathCMakeLists.txt
More file actions
274 lines (253 loc) · 13.7 KB
/
Copy pathCMakeLists.txt
File metadata and controls
274 lines (253 loc) · 13.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# ============================================================================
# Laige — Legendary AI Game Engine
#
# Root CMake project. Rules implemented here (see AGENTS.md and PRD.md):
# - NFR-8.8 CMake >= 3.22; single configure; no network access to build
# - NFR-8.9 static + shared library builds (LAIGE_BUILD_SHARED)
# - NFR-8.10 C++20; -Wall -Werror on the engine; no exceptions/RTTI
#
# Roadmap: M0-REPO-01 created the skeleton; M0-BUILD-01 adds the
# laige-core target, the sanitizer/test options, and the canonical
# command set (docs/getting-started/building.md is the source of truth);
# M0-DEP-01 adds the vendored-dependency lock check (deps.lock).
# Every engine target is passed through laige_apply_engine_policy().
# ============================================================================
cmake_minimum_required(VERSION 3.22)
# LANGUAGES includes C from M2-GL-01 on: the vendored C dependencies
# (GLFW, GLAD — deps.lock) compile in C targets defined at the root
# scope (deps/glfw's own, and the laige-glad target), so C must be
# enabled in the root scope, not only inside deps/glfw's subproject.
project(laige
DESCRIPTION "Laige — Legendary AI Game Engine"
LANGUAGES C CXX)
# ---------------------------------------------------------------------------
# Engine-wide language policy (NFR-8.10)
# ---------------------------------------------------------------------------
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# MSVC: CMake's Windows platform module adds /EHsc to CMAKE_CXX_FLAGS by
# default (CMP0117 NEW, CMake >= 3.20). The engine's no-exception policy
# (NFR-8.10) supplies /EHs- /EHc- per target via
# laige_apply_engine_policy(); leaving the platform /EHsc in place makes
# the two collide on every engine target's command line (cl D9025). Strip
# the platform default so each target's policy flags are the single source
# of truth for the exception model.
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
string(REGEX REPLACE "([/-])EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
endif()
# MSVC: force the MS STL off its checked-iterator debug mode in every
# target of this build (engine, tests, vendored dependencies). CMake's
# default MSVC Debug flags define _DEBUG, which makes the STL default to
# _ITERATOR_DEBUG_LEVEL=2: in that mode every STL container instance
# gets a heap-allocated iterator-proxy object in its constructor, so the
# engine's zero-allocation invariants (the M1-ECS-03 churn test, the
# M1-HEAD-01 headless run test) would measure a windows-msvc-only
# baseline that the other P0 platforms never enable — GCC/Clang/AppleClang
# compile without checked iterators by default. The define is build-wide
# (not per-target) because the MS STL enforces one _ITERATOR_DEBUG_LEVEL
# per linked binary: mixing engine targets compiled with 0 against
# GTest objects compiled with 2 fails the link (LNK2038). Disabling it
# build-wide makes the Windows Debug build measure the same allocation
# behavior as the rest of the P0 matrix. The proxies are an STL debug
# aid, not engine behavior — they are allocated in container setup,
# never on hot paths.
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
add_compile_definitions(_ITERATOR_DEBUG_LEVEL=0)
endif()
# Both the static (default) and shared (LAIGE_BUILD_SHARED) library variants
# are position-independent so they link identically into games and tools
# (NFR-8.9).
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# Canonical commands always pass -DCMAKE_BUILD_TYPE explicitly
# (roadmap/README.md §1); default to Debug when nothing is given.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
# Predictable artifact locations; canonical commands reference build/bin/.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
# Test registration (unit tests ship with every implementation step).
enable_testing()
# ---------------------------------------------------------------------------
# Options (M0-BUILD-01). Canonical command forms that reference these flags
# are documented in docs/getting-started/building.md (source of truth).
# ---------------------------------------------------------------------------
# NFR-8.9: engine libraries build static by default; ON switches engine
# targets to shared libraries.
option(LAIGE_BUILD_SHARED
"Build engine libraries as shared libraries (OFF: static)" OFF)
# Test suite under tests/ (default ON). Every M0 implementation step lands
# its unit tests in the same change; this option lets CI do a library-only
# build when a step needs one.
option(LAIGE_BUILD_TESTS "Build the test suite (tests/)" ON)
# Sanitizer builds (NFR-8.2). Mutually exclusive: a build tree is either
# instrumented with ASan+UBSan or with TSan, never both.
option(LAIGE_ASAN
"Instrument the whole tree with AddressSanitizer + UBSan" OFF)
option(LAIGE_TSAN
"Instrument the whole tree with ThreadSanitizer" OFF)
# Reserved for the optional scripting module (M4). No effect in M0; declared
# now so later canonical commands can name it without a breaking option
# introduction. (CORE-004: no wiring added before it is needed.)
option(LAIGE_SCRIPT
"Reserved: scripting module support (no effect in M0)" OFF)
if(LAIGE_ASAN AND LAIGE_TSAN)
message(FATAL_ERROR
"LAIGE_ASAN and LAIGE_TSAN are mutually exclusive; configure two "
"separate build trees (canonical: build-asan and build-tsan).")
endif()
# Sanitizer instrumentation (NFR-8.2) is applied to the whole tree — engine
# libraries, tests, and future tools — so a report anywhere fails the
# build loudly (CORE-008: no silent failure). Flags are set before any
# target is defined so every target in this tree inherits them.
if(LAIGE_ASAN)
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# MSVC 2022 (PRD §6 P0): ASan is full; UBSan is the supported subset.
set(_laige_sanitizer_flags "/fsanitize=address")
else()
# UBSan reports are made fatal (-fno-sanitize-recover=all); frame
# pointers are kept so ASan stack traces stay usable.
set(_laige_sanitizer_flags
"-fsanitize=address,undefined -fno-sanitize-recover=all -fno-omit-frame-pointer")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_laige_sanitizer_flags}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${_laige_sanitizer_flags}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${_laige_sanitizer_flags}")
elseif(LAIGE_TSAN)
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
set(_laige_sanitizer_flags "/fsanitize=thread")
else()
set(_laige_sanitizer_flags "-fsanitize=thread")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_laige_sanitizer_flags}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${_laige_sanitizer_flags}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${_laige_sanitizer_flags}")
endif()
# ---------------------------------------------------------------------------
# Vendored dependency lock (M0-DEP-01; PRD §11, NFR-8.6, DEP-005)
# ---------------------------------------------------------------------------
# deps.lock pins every vendored dependency under deps/ (name, version,
# source URL + commit, tree SHA-256, license, justification). This check
# re-hashes the vendored trees on every configure and fails loudly on any
# drift, missing tree, or unlisted vendored directory (CORE-008). It runs
# for every build tree, including library-only builds.
include(cmake/laige-deps-lock.cmake)
laige_deps_verify_lock()
# ---------------------------------------------------------------------------
# Engine target policy (NFR-8.10, AGENTS CORE-010)
# ---------------------------------------------------------------------------
# Every engine target MUST be passed through laige_apply_engine_policy():
# C++20, warnings-as-errors, exceptions and RTTI disabled. The MSVC options
# are the documented equivalent of
# -Wall -Werror -fno-exceptions -fno-rtti: /EHs- /EHc- clear C++ exception
# handling (Microsoft /EH reference), /GR- disables RTTI, and
# _HAS_EXCEPTIONS=0 switches the MS STL to its no-exception code paths:
# the STL gates its own try/catch (iosfwd _TRY_IO_BEGIN/_CATCH_IO_,
# yvals.h _TRY_BEGIN/_CATCH) on the _HAS_EXCEPTIONS macro, not on the /EH
# flags — with /EHs- alone it would still emit catch blocks that the
# compiler cannot unwind (cl C4530, fatal under /WX).
# _ITERATOR_DEBUG_LEVEL=0 (see the MSVC block above) keeps the Windows
# Debug build's STL container allocation behavior aligned with the other
# P0 platforms.
#
# The warning/language flags are PRIVATE: they govern this target's own
# translation units and must not leak into consumers (CPP-010) — a game
# linking the engine keeps its own compiler policy. The C++20 *requirement*
# does propagate (INTERFACE compile feature): engine headers are C++20, so
# consumers must build at least C++20.
function(laige_apply_engine_policy target)
# PUBLIC: this target compiles as C++20 and consumers are required to be
# C++20 as well (engine headers are C++20, NFR-8.10).
target_compile_features(${target} PUBLIC cxx_std_20)
# Every engine target is C++-only: vendored C sources compile in their
# own targets (deps/glfw's, and the laige-glad C target from M2-GL-01
# on), which keep the plain compiler policy.
if(CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang|AppleClang)$")
target_compile_options(${target} PRIVATE
-Wall -Werror -fno-exceptions -fno-rtti)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_options(${target} PRIVATE
/W4 /WX /EHs- /EHc- /GR-)
# See the function header: the MS STL needs _HAS_EXCEPTIONS=0 to take
# its no-exception code paths (same define GTest's own no-exception
# targets use; deps/googletest/cmake/internal_utils.cmake).
target_compile_definitions(${target} PRIVATE _HAS_EXCEPTIONS=0)
else()
message(FATAL_ERROR
"laige: no engine compiler policy for '${CMAKE_CXX_COMPILER_ID}'; "
"supported: GNU, Clang/AppleClang, MSVC 2022 (PRD §6).")
endif()
endfunction()
# ---------------------------------------------------------------------------
# SimMath pinned-math policy (M0-CORE-03; ADR 0002, PRD §10.3)
# ---------------------------------------------------------------------------
# Every target that carries deterministic sim math MUST be passed through
# laige_apply_simmath_policy(). In M0 that is laige-core (the SimMath
# home) and its tests; from M1 on, every sim module (laige-sim, and
# authoritative-sim code in laige-net/laige-server) joins the list.
#
# The flags implement ADR 0002's pinned set for the fp32_pinned backend
# (full rationale in src/laige-core/include/laige/sim_math.h):
#
# GCC / Clang / AppleClang:
# -ffp-contract=off a*b+c is never fused into a single-rounding
# FMA (protects SimMath::lerp / ::length's
# documented two-rounding)
# -fno-associative-math sums are never reassociated (already the
# default; passed explicitly so the pinned set
# is visible on every compile line)
# MSVC 2022:
# /fp:precise the documented precision model; MSVC does not
# FMA-contract C expressions and never
# reassociates at this setting (passed
# explicitly — it is the default — so the
# pinned set is visible on every compile line)
#
# Banned in sim translation units, all compilers: -ffast-math /
# -funsafe-math-optimizations / /fp:fast, floating-point intrinsics,
# rounding-mode changes, and FP exception modes (re-audited at every
# toolchain upgrade, ADR 0002).
function(laige_apply_simmath_policy target)
if(CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang|AppleClang)$")
target_compile_options(${target} PRIVATE
-ffp-contract=off -fno-associative-math)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_options(${target} PRIVATE /fp:precise)
else()
message(FATAL_ERROR
"laige: no simmath compiler policy for '${CMAKE_CXX_COMPILER_ID}'; "
"supported: GNU, Clang/AppleClang, MSVC 2022 (PRD §6).")
endif()
endfunction()
# ---------------------------------------------------------------------------
# Modules (PRD §10.1 module map)
# ---------------------------------------------------------------------------
# One directory per module. laige-core is the M0 foundation
# (M0-BUILD-01); laige-sim is the first module beyond it (M1-ECS-01);
# laige-render lands the GL infrastructure in M2-GL-01.
# Later milestones add their targets in place.
add_subdirectory(src/laige-core)
add_subdirectory(src/laige-sim)
add_subdirectory(src/laige-render)
# Samples (M1-SAMPLE-01): the hello.laige headless template game.
# Unconditional (not test-gated): the sample is a shipped project, and
# the CI detcheck step builds and runs it from the default tree. Its
# binary lands at the source-tree path samples/hello/bin/hello (its own
# CMakeLists sets RUNTIME_OUTPUT_DIRECTORY — see there why).
add_subdirectory(samples/hello)
# ---------------------------------------------------------------------------
# Tests (gated by LAIGE_BUILD_TESTS; conventions in tests/README.md)
# ---------------------------------------------------------------------------
if(LAIGE_BUILD_TESTS)
add_subdirectory(tests)
# Dev tools that need the built engine library (gated with tests: a
# library-only build does not need them).
add_subdirectory(tools/fuzz) # M0-CORE-07: laige-fuzz
add_subdirectory(tools/bench) # M0-CORE-08: laige-bench
add_subdirectory(tools/api) # M0-TOOL-01: laige-api-scanner
add_subdirectory(tools/detcheck) # M0-TOOL-02: laige-detcheck
add_subdirectory(tools/run) # M1-HEAD-01: laige-run (+ smoke test)
add_subdirectory(tools/replay) # M1-DET-03: laige-replay
endif()