ADR 0007: The Foundational core.h Header and Include Boundary¶
Status¶
Accepted.
Context¶
Ludus had a de facto universal vocabulary — the fixed-width type aliases in
ludus/foundation/base/types.h — but its universality was accidental: types.h
was included directly by only two .cpp files yet reached ~every translation
unit transitively, pulled in by ~28 other headers. Nothing stated, in one
place, what a Ludus source file may assume is available, and a routine header
refactor could break unrelated files. In parallel:
defines.handdefines.hppwere near-duplicates (both definedLUDUS_INLINEandnullptr_t;defines.hppadditionally carried the build-flavor macros and was missing from the CMakeFILE_SET);- OS/platform detection lived above the foundation, in the platform (windowing) module, so "am I on macOS?" required depending on a window library — a blocker for the planned macOS / Vulkan / Metal / D3D12 work;
- there was no PCH and, more importantly, no policy to stop a future PCH from silently becoming the dependency model.
The full audit, alternatives, and trade-offs are in
docs/architecture/foundational-headers.md.
Decision¶
Adopt a two-tier ("Candidate D") model with an explicit, contractual foundation and everything else opt-in.
-
Band 1 —
ludus/foundation/base/core.his THE foundational header. It is the one header a translation unit may rely on being universally available. It provides the fixed-width types, the build/OS/arch/compiler configuration macros, the codegen attribute/hint macros,Move/Forward/DerivedFrom/nullptr_t, and the assertion entry points — and nothing heavier.core.his what a file may rely on; it is not mandatory boilerplate, and a file that needs only part of the foundation may include the specific Band-0 header. -
Band 0 — macros only, no code.
config.howns OS-family, CPU-arch, and build-flavor detection (moved down from the platform module);compiler.howns compiler identity and the attribute/hint macros.defines.h/defines.hppare removed andcompiler.hpprenamed tocompiler.h. -
Band 2 — everything else is explicit. Containers, strings, logging, profiling, math, threading, filesystem, and smart pointers beyond the core are included by the files that use them. No reliance on accidental transitive includes above the foundation line (Chromium/Abseil discipline).
-
PCH is a build accelerator only.
LUDUS_ENABLE_PCH(default OFF) precompiles exactlycore.h. The default build (PCH off) is the guarantee that no file depends on a PCH-only symbol; a CI job exercises the PCH-on path. -
Mechanical enforcement. A header-self-sufficiency compile gate (every public header compiles standalone) and a narrow include-boundary gate (the foundational headers pull no strings/containers/heavy STL; no public header pulls heavy STL or a private header) run in CI and from
./scripts/check.
Consequences¶
The engine now has a single, documented answer to "what is always available,"
decoupled from transitive luck; portability decisions have a home at the
foundation; the duplicate/mis-packaged defines headers are gone. Build health
is preserved: core.h is cheap (only <cstdint>/<cstddef>/<type_traits>/
<utility> plus the assertion policy header), the heavy facilities stay opt-in
and budgeted (ADR 0004/0005), and the boundary is enforced rather than merely
documented.
This reinforces, and does not replace, ADR 0003 (standard-library policy),
ADR 0004 (type-erase heavy templates), and ADR 0005 (build-time budgets). It is
forward-compatible with a later C++20 modules migration: core.h is the natural
first module interface unit and the Band-2 explicit-include discipline maps onto
import boundaries. AGENTS.md carries the day-to-day Allowed / Required
explicitly / Forbidden summary.