Repository map
Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. File counts were computed from the Git tree of the pinned commit and link edges were read from each module's CMakeLists.txt; the tests named exist and are registered in CMake, but nothing was configured, built or executed for this page.
CNA is a module-oriented monorepo. Production code lives under modules/, build policy under cmake/, shared fixtures and cross-module suites under tests/, and generators, audits, launchers and harness sources under tools/ and scripts/. This page is the map of that layout at snapshot 009d40f5: what each directory holds, how a module directory is shaped, which headers are public, Internal or private, what is generated, where the vendor boundaries run and which tests belong to whom. Read it before opening a source file you did not write; the lookup "which part of CNA owns this behaviour?" is a separate page, Source ownership.
How the three layout pages divide the work. This page is the map: directories, module shape, header classes, generated files, vendor boundaries, test ownership. Source ownership answers "who owns this behaviour" by symbol and subsystem. The physical module dependency map draws the link edges between the module targets. File and header counts below were computed from the Git tree of the pinned commit; nothing was built or executed for this page. The user-level view of the same layout is Architecture: module layout and Architecture: directory structure.
Top-level map
Every row is a directory (or file group) at the repository root, with the number of files Git tracks in it at this snapshot. The right-hand column says when you would edit there. Counts describe tree shape, not importance.
| Path | What it holds at this snapshot | Modify when… |
|---|---|---|
modules/4,798 files | 23 directories: 22 declared framework modules plus renderers/ (21 implementation families and the two shared helper directories common/d3d and common/mojoshader). Public and Internal headers, implementations, module-owned tests, examples and benchmarks, and each module's own CMakeLists.txt. | Changing CNA behaviour or API. This is where nearly every production change lands. |
cmake/196 files | Platform, audio, SDL-availability and renderer selection and the renderer registry; third-party setup (ThirdParty*.cmake, native X11 and Wayland detection); build policy (BuildPerformance, SharedRuntimeLibrary, SharpRuntimeConsumption, ApplePlatform); test registration (UnitTests, TestHelpers, TestDisplayPolicy, Harnesses, DirectXParityTests, XnaPipelineParityGates); script-mode gates under Tests/; toolchain files for mingw-w64 and iOS; two templates; and 122 files under patches/. | Adding a backend, option or target, or changing how the configuration is composed. See CMake architecture. |
tests/2,340 files | Data and cross-module material, not the unit tests of any one module: assets/ (1,139 files, mostly glTF, XNA 4.0 and XNB fixtures), gltf-l7/ (578: rendered-pixel golden images and reports for four renderers), reference/xna40/ (566: the recorded Content Pipeline oracle data), fixtures/ (compiled-effect and Direct2D fixtures that tests replay), interop/, support/ (a header-only compiled-effect conformance suite), modules/ (15 minimal-link module probes), apple/ (the Apple smoke application), and two C++ sources at the root, HarnessAssertionPolicy.cpp and OracleCorpusTests.cpp. | A contract spans several modules, a fixture or reference asset changes, or a module's link closure must be pinned. See Where tests live. |
tools/448 files | Sources of CNA's own command-line tools and harnesses (the cna-content front end under tools/content, the glTF and CNB converters), the oracle and reference tooling (xna-pipeline-oracle, xna-oracle, xna-sample-sweep, fna-reference, cna-reference), platform launchers and audits (tools/platform: 64 files including run_gpu_tests_private.sh, x11_test_server.sh, wayland_test_server.sh and the SDL containment audits), the C API generators (tools/c-api), the shader-package generator and the build-performance scripts (tools/build). | Automating or auditing a repository invariant; changing a tool's own behaviour. |
scripts/65 files | Repository gates that CTest and CI run (check_renderer_identities.py, check_renderer_combinations.py, check_module_link_closure.py, check_test_display_isolation.py, the CNAEXT checks), corpus and oracle runners, the Wine, DXVK and vkd3d wrappers, the browser-test drivers and scripts/ci/clone_siblings.sh. | A gate's rule changes, or a new invariant deserves a script. |
docs/240 files | Design notes and contracts: docs/physical-modules.md, per-renderer notes, the platform notes, the C API documents under docs/c-api, ADRs under docs/adr, recorded reports. | A documented contract changes with the implementation. Treat a document as evidence of intent and check it against the code: for example the physical-modules note says the top-level examples/ holds exactly one thing, but the tree also has a loose examples/xvfb_screenshot_demo.cpp that is not a top-level target: only the EasyGL and SDL_Renderer example CMake files compile it, as ad hoc test targets. |
.github/workflows/20 files | The CI workflows: 28 jobs over Linux, macOS, iOS, Windows (MSVC and MinGW under Wine) and a headless browser. | Validation coverage or environment changes. See what CI covers. |
third_party/, vendor/ | Dependency boundary: four submodules and four in-tree vendored libraries under third_party/, and the googletest submodule under vendor/. | Only deliberate dependency maintenance. See Third-party and vendor boundaries. |
examples/18 files | The cross-renderer golden-image corpus examples/golden/, loaded at run time through repository-root-relative paths, plus the loose file mentioned above. Module examples live with their module, not here. | A golden image is regenerated. Do not add new examples here: a module-specific example belongs in that module's examples/. |
spikes/95 files | 26 existence-gate probe directories, one per question a new backend or platform had to answer before real code was written (for example the terminal, Wayland, Win32, WebGPU and several real-XNA behaviour probes). | Recording a new probe. They are evidence for a decision, not production code. |
| Planning, audit and history trees | plans/ (109 files; the plan identifiers quoted in CMake comments, such as GL4-0016 or SMG-0039, refer to them), plan/, audit/ (2,493 files, mostly per-source-file audit records that mirror the tree), remediation/, modularization/ (142 files: the physical-move maps and tools such as check_include_reachability.py), integration/, misc/, and root notes such as NEXT.md, AUDIT.md, TODO.md and known_bugs.md. | Recording intent or history. None of it is a build input; use it to learn why a rule exists, then confirm what executes in the source. |
| Root files | CMakeLists.txt, CMakePresets.json, .gitmodules, Doxyfile, README.md, the contributor rules CLAUDE.md and AGENTS.md, CHANGELOG.md, and main.cpp, a hello-world stub that no CMake file references. | Root policy, presets, version identity. |
There is no top-level include/ or src/. Consumer-visible headers live under each module's own include/, and implementations under its src/. A production translation unit outside every declared module fails the configure, and so does a root-level src/ or include/ directory reappearing ("legacy global tree reappeared"): see modules/CMakeLists.txt. A search that starts by looking for a shared include root will find nothing; start from the owning module.
Physical module shape
modules/<name>/ ├── CMakeLists.txt target and dependency declaration; collects its own sources ├── include/ public and cross-module headers, spelled as consumers include them │ ├── Microsoft/... XNA-shaped API (Microsoft/Xna/Framework/..., Microsoft/Devices, Microsoft/Phone) │ └── CNA/... CNA-owned surface; CNA/Internal/... holds cross-module internal contracts ├── src/ implementation and module-private headers │ ├── Xna/ XNA API implementation │ ├── Internal/ CNA::Internal engine parts │ └── CnaExt/ CNAEXT extension surfaces (single-area modules stay flat) ├── tests/ GoogleTest sources mirroring the namespace path ├── examples/ demos and example programs, registered by the module's own CMake └── benchmarks/ only diagnostics and inspector have one
The include tree mirrors the namespace-facing path, so #include "Microsoft/Xna/Framework/Graphics/Texture2D.hpp" resolves from modules/graphics/include and the spelling is identical wherever a consumer sits. A module's src/ uses the area convention Xna/, Internal/, CnaExt/ (see modules/graphics/CMakeLists.txt for the globs); the platform module instead gives every implementation its own directory (Sdl3/, Sdl2/, Win32/, X11/, Wayland/, Headless/, Terminal/) beside Common/ and the pieces only the Unix desktop backends share (Xkb/, Freedesktop/, Posix/, Linux/), and the audio module separates Platform/ (devices) from Backend/ (mixers). The CNA umbrella composes module targets as an INTERFACE library; it does not compile into one giant library, and cmake --build <dir> --target CNA is not a buildable target (the umbrella and its link closure).
- How a module becomes a target.
modules/CMakeLists.txtdefinescna_add_module(target alias sources...): a STATIC librarycna_<name>with the aliasCNA::<Alias>, linked PUBLIC tocna_build_configand publishing that module's owninclude/as its PUBLIC include root. Sources are collected withfile(GLOB … CONFIGURE_DEPENDS)from the module's ownsrc/(the graphics core globs itsXna,InternalandCnaExtareas, a renderer family globs only its ownsrc/*.cpp, not recursively), so adding a.cppthere needs no CMake edit. The one module that lists its sources by hand isc-api. - Naming exceptions.
gamer-services,netandvideo-ffmpegcalladd_librarydirectly (CNA_GamerServices,CNA_Net,cna_video_ffmpeg);corealso defines the header-onlycna_core_headers(CNA::CoreHeaders) thatmath,storageandphonelink instead of the archive;content-pipelineiscna_content_pipelinewith the aliasCNA::ContentPipelineBuild;c-apiiscna_c_api, a shared library (static under Emscripten); each renderer family iscna_renderer_<family>with-replaced by_. - One documented ownership exception. The GDI renderer compiles eight software-module CPU-2D translation units into its own archive; their physical owner stays
renderers/software. Every other file's directory is its CMake owner. - Renderer families need not have every subdirectory. Fifteen of the 21 families have a
tests/directory (and so do both shared helpers);freedirect,gdi,headless,portablegl,sdl-rendererandstubkeep their tests as example programs underexamples/.
The 23 directories and their targets
The direct CNA link edges below were read from each module's CMakeLists.txt (PUBLIC unless marked); sharp-runtime components and third-party libraries are left out. "Umbrella" means the target is one of the parts of the CNA INTERFACE library in modules/CMakeLists.txt. The three intentional static-archive cycles (graphics and input, audio and media, graphics and the selected renderer) are why some edges are PRIVATE.
| Directory | Target (alias) | Umbrella | Owns | Direct CNA link edges |
|---|---|---|---|---|
core | cna_core (CNA::Core), cna_core_headers | yes | Base types, logging and exceptions, TargetPlatform, the renderer identity enum and GraphicsRendererSelection, the CNAEXT marker macro | none |
math | cna_math | yes | Vectors, matrices, quaternions, colours, bounding volumes, curves | cna_core_headers |
diagnostics | cna_diagnostics | yes | Counters, zones and frame history, compiled to nothing when CNA_DIAGNOSTICS=OFF | none |
platform | cna_platform | yes | IPlatform and its implementations; the module that links the native windowing and host libraries (privately on desktop; audio and the SDL-by-identity or SDL-upstream renderer families link SDL for their own backends) | cna_core_headers |
graphics | cna_graphics_core (CNA::GraphicsCore) | yes | XNA graphics API, GraphicsDevice, renderer interfaces, descriptors and the generated registry | cna_math, cna_core, cna_diagnostics, cna_platform; PRIVATE cna_input and every selected renderer |
input | cna_input | yes | Keyboard, mouse, gamepad, touch and gestures | cna_graphics_core, cna_math, cna_core, cna_platform |
audio | cna_audio | yes | XNA audio and XACT, the audio devices and mixers | cna_core, cna_diagnostics, cna_math; PRIVATE cna_platform, cna_media, cna_input |
media | cna_media | yes | MediaPlayer, MediaLibrary, the Video surface (link-complete without FFmpeg) | cna_audio, cna_graphics_core; PRIVATE cna_input, and cna_video_ffmpeg when FFmpeg is enabled |
video-ffmpeg | cna_video_ffmpeg (CNA::VideoFfmpeg) | no | The optional FFmpeg backend; entered only when FFmpeg was found | cna_build_config; linked into cna_media only |
content | cna_content | yes | ContentManager, XNB and CNB readers and writers, the canonical pipeline API under CNA/Content/Pipeline | cna_graphics_core, cna_audio, cna_media, cna_math, cna_core |
content-pipeline | cna_content_pipeline (CNA::ContentPipelineBuild) | no | Build-time-only components: the FreeType .spritefont route, FFmpeg importers, FBX and .x readers, the external effect-compiler service, the XNA Content.Pipeline facade | cna_content; linked by cna_content_compiler and the content-pipeline test targets, never by the umbrella |
storage | cna_storage | yes | StorageDevice, StorageContainer and path containment | cna_core_headers |
runtime | cna_runtime | yes | Game, GameWindow, GraphicsDeviceManager, components, the project graphics profile | cna_graphics_core, cna_input, cna_content, cna_audio, cna_media, cna_core, cna_diagnostics, cna_math, cna_platform |
devices | cna_devices | yes | The XNA-compatible Microsoft::Devices sensors and vibration | cna_runtime, cna_graphics_core, cna_core, cna_math |
devices-ext | cna_devices_ext | yes | CNA device extensions: camera, clipboard, dialogs, tray, power, locale, URL launcher | cna_runtime, cna_graphics_core, cna_core, cna_math, cna_platform; never the XNA device base |
phone | cna_phone | no | The Microsoft::Phone application shell | cna_runtime, cna_core_headers |
graphics-ext | cna_graphics_ext | yes | The CNAEXT engine layer | cna_graphics_core |
design | cna_design | no (opt-in) | Framework.Design type converters | cna_math |
inspector | cna_inspector and the cna-inspector executable | no | Inspector agent, bridge and browser UI; defined only with CNA_BUILD_INSPECTOR | cna_diagnostics, cna_core_headers |
gamer-services | CNA_GamerServices (CNA::GamerServices) | no | GamerServices, Guide, Avatar, local persistence; entered only with CNA_ENABLE_NET | cna_runtime, cna_storage |
net | CNA_Net (CNA::Net) | no | Microsoft::Xna::Framework::Net over ENet; entered only with CNA_ENABLE_NET | CNA_GamerServices, enet |
c-api | cna_c_api (CNA::CApi) | no | The experimental C ABI (0.29.0; public headers held to a C99 consumer floor, CNA's own C sources built as C17); entered only with CNA_BUILD_C_API | PRIVATE cna_core, cna_platform, cna_runtime, cna_graphics_ext, cna_storage, cna_content, cna_media, cna_devices, cna_devices_ext, CNA_Net, CNA_GamerServices |
renderers | cna_renderer_<family> for each of 21 families | the selected family or set | Backend translation of resources, draws, presentation and synchronisation behind IGraphicsRenderer | PRIVATE reverse edges to cna_graphics_core, cna_core, cna_math |
Rows for graphics and renderers hide the interesting part: the graphics core links every selected family privately (the factory edge) and each family links the graphics core back (the reverse edges), which is why static link order is a declared invariant rather than an accident. Both halves are traced in the CMake architecture chapter. The generated module index lists the same directories with header, source and test-file counts and entry-point headers; its "test files" column counts every file under tests/, not the 904 C++ test sources discussed below.
Public, Internal and private headers
"Public" is a tree-shape word at this snapshot, not an export mechanism. The C++ framework has no install() rules, every module publishes its whole include/ directory PUBLIC, and nothing stops a target that links a module from including a header under CNA/Internal. The classes below are conventions enforced by review and by the gates in What keeps this map true.
| Class | Where | Meaning and example |
|---|---|---|
| XNA-shaped public API | include/Microsoft/… | The names and shapes of XNA 4.0 and the Windows Phone shell. Example: GraphicsDevice.hpp. |
| CNA-owned public surface | include/CNA/… outside Internal/ | Facilities and CNAEXT extensions that are not XNA: GraphicsRendererSelection.hpp, RendererCapabilityProfile.hpp, and the engine layer under graphics-ext. Every declaration that is not part of XNA 4.0 is tagged CNAEXT through CNAHelper.hpp. |
| Cross-module internal contracts | include/CNA/Internal/… | Contracts between modules that are not for consumers: IGraphicsRenderer.hpp and the descriptor and registry headers beside it, and each family's own CNA/Internal/Renderers/<Family>/ root. They live in an include root, so "Internal" is a naming and review convention, not a visibility barrier. |
| Module-private headers | src/… | Headers next to the implementation. No module adds another module's src/ as an include root, with two deliberate exceptions: every renderer target adds modules/platform/src PRIVATE (the SDL-backed families on the platform SDL audit's allow-list reach the one edge Sdl3RendererInterop.hpp), and the test build adds modules/audio/src so an implementation test can see a private audio device. |
| C ABI headers | modules/c-api/include/CNA/C/*.h | 61 plain-C headers with their own version (ABI 0.29.0, experimental) and their own build gates. See C API and bindings architecture. |
| Generated headers | build tree | CNA/Version.hpp is rendered into <build>/generated/include and added to core's include roots; see Generated and checked-in generated files. |
The generated public header index lists 808 non-Internal headers under include/CNA and include/Microsoft in 21 modules; it says nothing about which of them are supported API.
Subsystem families
Group modules by the question they answer and the boundary a change crosses, not by directory name. Each row is a family of modules that usually change together; the last column states the ownership fact a reviewer should hold in mind. For the per-object lifetime rules behind these statements see Ownership and lifetime master map and What a human maintainer inherits.
| Family | Modules | Calls and ownership |
|---|---|---|
| Orchestration | runtime | Game coordinates the platform, services, components and frame callbacks; it owns the platform it installs and the GraphicsDevice value member (Runtime module internals). |
| Host boundary | platform, input, audio | Platform implementations emit events and provide narrow services; nothing outside platform links a platform library. Input state is process-wide. Audio devices and mixers are selected by their own axis (Platform architecture). |
| Rendering | graphics, graphics-ext, renderers/* | GraphicsDevice owns public resource tracking; the selected renderer translates commands. graphics-ext is the CNAEXT layer above the same device (Graphics architecture). |
| Assets | content, content-pipeline, media | Runtime load and cache live in content together with the canonical pipeline engine and the XNB and CNB writers; content-pipeline holds only what must never ship in a game. Neither the pipeline module nor FreeType is in a game's link closure (Content architecture). |
| Interop | c-api | The experimental C ABI (public headers held to a C99 consumer floor) converts handles and errors across the C++ boundary; a C++ change can become ABI, lifetime and compatibility work. Opt-in through CNA_BUILD_C_API, which requires CNA_ENABLE_NET=ON. |
| Foundations | core, math, storage, diagnostics | Shared value types, identities and services; keep upward dependencies out. math and storage link only the header-only cna_core_headers. |
| Device and phone compatibility | devices, devices-ext, phone | Sensors, device extensions and the Windows Phone shell sit above runtime; the extension module never depends on the XNA device base. |
| Optional services and tooling | net, gamer-services, video-ffmpeg, design, inspector | Each is entered or linked only when asked for (CNA_ENABLE_NET, CNA_ENABLE_VIDEO, CNA_BUILD_INSPECTOR) or named on a link line. A default build says nothing about them. |
How to find the owner
- Find the public symbol's declaration with a search under the module
include/directories, for examplerg -n "class SoundEffect\b" modules/*/include. The directory you land in is the candidate owner. - Find the out-of-line definition, the constructor and every place the state is mutated in that module's
src/. A static XNA API (Keyboard::GetState,StorageDevice) may reach an ambient platform rather than a context you can see. - Trace factory and registry creation instead of assuming the directory is selected. For a renderer that means the identity map in
cmake/RendererRegistry.cmake, the family's*RendererDescriptor.cppand the generatedCnaRendererRegistry.generated.cpp; for a platform,PlatformFactory; for audio, the compiled-in device and mixer. - Search the focused tests in the owning module's
tests/first, then the conformance and integration tests that name the symbol, then the renderer-family example programs. - Read the module's
CMakeLists.txtbefore crossing a boundary: which targets it links, whether the link is PUBLIC or PRIVATE, and whether the module is entered conditionally. - Confirm the answer against Source ownership, the module dependency map and the generated module index and public header index, which give source-pinned entry points.
Generated and checked-in generated files
Two different things are called "generated". Some files are produced into the build tree during configure or build and never committed; others are committed but must stay derivable from their sources, and a gate fails when they drift. Before committing a change to either kind, find the generating rule and reproduce the output from clean input.
| File | Produced by | Committed? | Guard |
|---|---|---|---|
<build>/generated/CnaRendererRegistry.generated.cpp | cmake/RendererRegistry.cmake from cmake/templates/CnaRendererRegistry.generated.cpp.in, compiled into cna_graphics_core | no | the descriptor gate and RendererIdentityRegistry |
<build>/generated/include/CNA/Version.hpp | cmake/Version.cmake from the version set in the root CMakeLists.txt | no | single source of the version string |
<build>/generated/cna_shared_library.cpp | cmake/SharedRuntimeLibrary.cmake (a one-line stub so libcna.so has a source) | no | only with CNA_SHARED_LIBRARY |
<build>/generated/wayland-protocols/ | wayland-scanner through cmake/PlatformWayland.cmake | no | only for CNA_PLATFORM=WAYLAND |
| the compiled-effects stock-effect header for EasyGL | a custom command in modules/renderers/easygl/CMakeLists.txt | no | only with CNA_EASYGL_COMPILED_EFFECTS |
.sdl-prebuilt-<key>/ in the source tree | the configure-time SDL sub-builds (the SDL prebuilt) | no (git-ignored) | a build manifest stamp |
spirv_shaders.hpp for Vulkan and SDL_gpu | compile_shaders.py beside each file (modules/renderers/vulkan/src/shaders/spirv_shaders.hpp) | yes, marked "do not edit by hand" | the SpirvPayloadValidation gate in a configuration that includes VULKAN, where spirv-val is installed |
*ShaderPackage.generated.hpp (engine layer and examples) | tools/shader_package/generate_shader_package.py | yes | the *ShaderPackageReproducibility tests re-derive a package with --check and skip (77) without shaderc; reproducibility tests are registered for most of the 20 shader packages in the tree but not all (none was found for the shadow-caster or modern-resource-interop packages) |
| the C ABI baseline, compatibility matrix, coverage inventory and limitations | the generators under tools/c-api | yes | five C API workflows and the CApi* CTest gates |
| the content-pipeline parity report | tools/xna-pipeline-oracle/parity_report.py | yes | the XnaPipeline* gates in cmake/XnaPipelineParityGates.cmake |
the glTF conformance corpus (tests/assets/gltf fixtures, manifests and vertex/index goldens) | scripts/regenerate-gltf-goldens.sh | yes | --check and --determinism in the glTF sanitizer workflow |
| rendered glTF goldens | scripts/gltf-l7-corpus.py --update-goldens | yes; the script requires --report-out with it and a second run that agrees byte for byte | run below an X server (normally xvfb-run -a) |
Third-party and vendor boundaries
Four mechanisms bring outside code into a CNA build, and each has a different rule for how you touch it. The general rule: third_party/ and vendor/ are external. CNA's build policy (warnings, sanitizers, debug-information and linker options) is attached only to targets whose source directory lies inside the repository and outside those two trees, so a change there is dependency maintenance, not a CNA edit.
| Kind | What | How it enters the build |
|---|---|---|
| Git submodules (five gitlinks) | third_party/SDL (pinned at cbe3fbe9), third_party/SDL_image (fcb9d0b1), third_party/SDL_mixer (3075d3ed), third_party/draco (1.5.7, 87867400), vendor/googletest (7e2c425d) | git submodule update --init, non-recursive. SDL, SDL_image and SDL_mixer are built at configure time into a persistent prebuilt directory; Draco is a subdirectory unless CNA_ENABLE_DRACO=OFF or a system package is chosen; googletest is added while CNA_BUILD_TESTS=ON. A missing submodule stops the configure with a named message. With CNA_ENABLE_SDL=OFF the SDL submodules are never touched. |
| Vendored in the tree | third_party/enet, third_party/stb, third_party/dr_libs, third_party/cgltf | Compiled or included directly (ENet only with CNA_ENABLE_NET). The module CMake files reach the vendored single headers through CNA_SOURCE_DIR rather than CMAKE_SOURCE_DIR, so a consumer that adds CNA as a subdirectory still finds them. |
| Sibling repositories | ../sharp-runtime (every build, its next branch), ../easy-gl with ../meta-gl (the five GL identities), ../free-direct with ../free-api (FREEDIRECT only) | Separate checkouts entered with add_subdirectory(../<repo>); CMake will not fetch them. sharp-runtime's location is the CNA_SHARP_RUNTIME_ROOT cache path. See the Building CNA sibling checkouts. |
| Fetched at configure time | FNA3D with MojoShader (pinned tag, 3240147), wgpu-native (v29.0.1.1), PortableGL (63a55db7), SDL_shadercross (1ff05bec) with SPIRV-Cross, and SDL2 (2.30.11) for CNA_PLATFORM=SDL2 | Only when the renderer, option or platform that needs them is selected. FNA3D's MojoShader also receives a series of local patches from cmake/patches (117 MojoShader patch files against one pinned revision), applied automatically and idempotently; SDL and SDL_shadercross have their own small series. Details in CMake architecture: third-party dependencies. |
Where tests live and who owns them
Test ownership follows source ownership. A module's unit tests live in that module's tests/, mirroring the namespace path, and are compiled into a per-module object group; renderer-family behaviour is exercised mostly by example programs in the family's examples/; only genuinely cross-module material sits in the top-level tests/. The counts follow the table; how the sources are assembled into executables is described on Test architecture.
| Location | Owns | Runs as |
|---|---|---|
modules/<name>/tests/ | Focused GoogleTest sources for that module | One object group, linked into the aggregate CnaTests and into that module's focused executable |
modules/renderers/<family>/tests/ and modules/renderers/common/*/tests/ | Renderer-policy suites that need no device (capabilities, descriptors, state mapping) | The renderers group, CnaRendererTests |
modules/<name>/examples/, modules/renderers/<family>/examples/ | Demos and the standalone pixel and smoke programs (879 *_test.cpp programs, outside the 904 and 12,610 figures) | Separate executables, each registered through cna_register_renderer_test or add_test in the module's own CMake |
modules/c-api/tests/ | The C API's consumer tests: mostly C files with their own main(), plus seven C++ files | Their own executables and CApi_* CTest entries; deliberately not part of CnaTests |
top-level tests/*.cpp | HarnessAssertionPolicy.cpp, OracleCorpusTests.cpp | The integration group, CnaIntegrationTests |
tests/modules/ | Fifteen minimal-link probes, one per module alias | Standalone executables with a paired link-closure gate |
tests/assets, tests/reference, tests/gltf-l7, tests/fixtures | Fixtures and recorded reference data, addressed by repository-root-relative literal paths | Read by tests; discovered CnaTests cases run with the repository root as their working directory |
The 904 C++ test source files counted by the site method (every .cpp under a tests/ or test/ directory, vendored code excluded) are distributed as follows, recomputed by path from the Git tree at this snapshot. The figure is a source inventory, not an executable case count and not a pass result.
| Owner | Files | Owner | Files |
|---|---|---|---|
| content | 170 | audio | 38 |
| graphics | 161 | net | 18 |
| graphics-ext | 92 | gamer-services | 14 |
| platform | 85 | devices-ext | 10 |
| renderer families and helpers (17 directories) | 69 | core | 9 |
| input | 47 | c-api (seven C++ files) | 7 |
| content-pipeline | 47 | design, phone (2 each) | 4 |
| media | 30 | diagnostics, inspector, storage (1 each) | 3 |
| devices | 27 | top-level tests/ (2 sources, 15 probes, 1 Apple smoke app) | 18 |
| math | 27 | one test-display fixture under cmake/Tests | 1 |
| runtime | 27 | ||
What keeps this map true
Most of the layout is enforced mechanically, so a map that disagrees with the tree is the map's fault. These are the gates to run or read when you move a file, add a module, or add a dependency edge.
- Source-partition validator in
modules/CMakeLists.txt: every.cppor.mmundermodules/must sit in a declared module'ssrc/,tests/,examples/orbenchmarks/tree (lists_cna_framework_modulesand_cna_renderer_modules); a legacy rootsrc/orinclude/fails. Moving a file between directories is a build-ownership change, not a rename. - Minimal-link probes in
cmake/Tests/ModuleProbes.cmake: fifteen tiny consumers of one module alias each, paired withModuleLinkClosure_*tests that runscripts/check_module_link_closure.pyover the generated link line and fail when a forbidden archive or library appears. The HEADLESS configuration additionally proves that renderer-neutral graphics needs no native graphics SDK. - Identity and discipline scripts:
scripts/check_renderer_identities.pyholds the CMake identity list, the registry map, the C++ enumeration and the C ABI header to one canonical table;scripts/check_renderer_target_discipline.pyandscripts/check_runtime_renderer_discipline.pykeep families from reading global scalars and keep renderer-specific decisions behind descriptors. - Include reachability:
modularization/tools/check_include_reachability.pychecks that every"CNA/..."or"Microsoft/..."include in a module translation unit resolves through a module graph written into the script itself. At this snapshot that graph is out of date (it lists 14 of the 22 declared framework modules;platform,diagnostics,content-pipeline,phone,c-api,design,inspectorandvideo-ffmpegare absent) and no CMake rule, test or workflow runs the script, so it is a manual aid rather than a gate that keeps this map true. - Configure-time SDL audits (the platform ratchet, the non-production SDL audit and the hot-path lint) keep SDL inside the platform module; see CMake architecture: gates that run at configure time.
The physical-modules note docs/physical-modules.md is a useful summary but is not a substitute for the CMake files it summarises: for example its dependency table omits the input, diagnostics and platform edges of cna_runtime that the module's own CMakeLists.txt declares. When the two disagree, the CMake file is what executes.
Deep dives on this topic
Long-form pages that explain the exact semantics, invariants and evidence behind this subject.
- Project records as evidence: plans, ledgers, versions, handoffs and re-audits — How to use and write CNA's plans, handoffs, audits and gates as evidence: roles, stable task IDs, executable ledgers, version coordinates, defect-ledger rules and documentation re-audits.
- The physical module architecture: ownership, targets and composition — How CNA's 22 framework modules and 21 renderer families own their targets, include roots, tests and examples, which target names cannot be guessed, and how to read a source path at snapshot 009d40f5.
Known issues in this area
Current defects, gaps and limitations at this snapshot that touch this subject.
- CNA-BUG-055: Stale whole-registry renderer counts survive outside check_renderer_identities.py's list: the C API's CORE.md and FEATURE_MATRIX.md say 50, core_ext.h says 46, ModuleProbes.cmake says 42, and CHANGELOG says 49 for a 50-identity release — CNA has 25 public renderer identities, yet the C API's backend-classification contract, a public C header's Doxygen, a CMake test header and the alpha.1 release notes still state obsolete totals that no count gate reads.
- CNA-BUG-232: docs/physical-modules.md has no row for modules/platform, omits the platform and diagnostics edges of runtime, input, audio and devices-ext, and says top-level examples/ holds only examples/golden — CNA's physical-module map, which check_renderer_identities.py keeps under count control, never mentions the platform module that input, runtime, audio and devices-ext link, and misdescribes the top-level examples directo
- CNA-VGAP-019: ModuleLinkClosure_* link-closure gates report CTest SKIP in every Ninja tree, so no Ninja-preset run and no CI job ever evaluates them — check_module_link_closure.py reads the make-only CMakeFiles/<target>.dir/link.txt and exits 77 when it is missing; the Ninja presets and every CI job either use Ninja or never run these tests, so CNA's module dependency
Related pages
The same subsystem is explained at four altitudes. These are the neighbouring pages at each one.
- Architecture
- Physical module dependency map · Architecture overview
- Internals
- Internals · CMake architecture
- Maintainer workflow
- Source ownership · What a human maintainer inherits
- Tests and validation
- Test architecture and change recipes
- Reference
- Module index · Public header index · Selection axes index