The CNA ecosystem: siblings, references and consumers
Evidence basis: source-verified at the pinned commit. Claims on this page were checked by reading the CNA source at commit c1c316b9; unless a sentence says otherwise, nothing here was built or executed. Sibling statements were read in each sibling repository at the revision named in the table (sharp-runtime 41b918c9, easy-gl deda7a42, meta-gl 20c8b2dc, xna4-spec fedc17aa, cna-samples 5db32e6, cna-examples ea33c9a2); they are evidence for those revisions, not for CNA c1c316b9. Counts quoted from sibling READMEs are those projects' own records.
CNA is not one repository. It builds against sibling libraries that are separate checkouts, it is audited against references it does not link, and it is exercised by consumer repositories that pin their own CNA revisions. This page maps those relationships as they stand for CNA snapshot c1c316b9: which repository provides what, when CMake needs it, where each sibling draws its own boundary, and which revision a statement about a sibling refers to. It is the orientation page for anyone setting up a build or deciding which repository a problem belongs to.
The dependency graph
REFERENCES (read or executed, never linked)
Microsoft XNA 4.0 XML docs + DLL metadata ---- representation census ------+
FNA source tree and FNA.dll ------------- behaviour, value diffs ----------+
genuine XNA 4.0 under Wine + DXVK ------- 39-scene pixel oracle -----------+
xna4-spec XML (searchable inventory; no CNA tool reads it) . . . . . . . . :
v
SIBLINGS (separate checkouts next to cna/) +------------------+
sharp-runtime (branch apple/m4-stabilization) ========== every build ===========> | CNA |
meta-gl ===> easy-gl - - - - - - three GL identities - - - - - >| snapshot |
| c1c316b9 |
+------------------+
|
CONSUMERS (pin their own CNA revision) v
cna-samples (Ms-PL) cna-examples (MIT) cna-template games, apps, language bindings
===> required - - > only when the matching renderer is selected ---> evidence input
| Repository | Role | When CNA needs it | Revision read for this page |
|---|---|---|---|
| sharp-runtime | C++23 implementation of a practical subset of .NET System.* | Every build; branch next | 41b918c9 (2026-09-20) |
| easy-gl | Toolkit-independent C++ wrapper over OpenGL and OpenGL ES (its README says C++20; its CMake requires cxx_std_23, PUBLIC) | Only for OPENGLES3, OPENGL33, WEBGL2 | deda7a42 (2026-08-22) |
| meta-gl | Low-level, type-safe C++23 layer for OpenGL ES 2.0 to 3.2 and desktop GL 3.3+; the foundation of easy-gl | Transitively, through easy-gl | 20c8b2dc (2026-09-03) |
| xna4-spec | Machine-readable XML transcription of the XNA 4.0 documentation | Never; a reference for human audits | fedc17aa (2026-09-13) |
| cna-samples | C++ ports of the XNA Game Studio 4.0 sample collection | Consumer | 5db32e6 (2026-10-03) |
| cna-examples | One application that catalogues live demonstrations of every CNA area | Consumer | ea33c9a2 (2026-09-13) |
None of these is vendored into CNA or included as a Git submodule, and CNA's CMake declares no pin or lock file for any of them (CI checks out the sharp-runtime branch that matches the run's branch, chosen by sibling_branch.sh, not a pinned commit): the revisions in the last column are the ones read for this page, not versions CNA promises to work with. Each sibling is a separately buildable, separately tested project. sharp-runtime in particular presents itself as a foundation for frameworks such as CNA, with CNA as its downstream consumer; sharp-runtime and easy-gl could each serve a project unrelated to XNA.
How the build finds its siblings
The graph above is what CMake does at configure time. The root CMakeLists.txt checks CNA_SHARP_RUNTIME_ROOT (default ../sharp-runtime) before anything else is built and stops with a message that names the missing checkout, says that git submodule update --init will not fetch it, and prints a copy-pasteable git clone fix, rather than failing later with a missing header. cmake/RendererSelection.cmake applies the same pattern to easy-gl: only when a GL identity is selected, it looks for the checkout at CNA_EASYGL_ROOT (a cache path, default ../easy-gl), adds it once even when several GL identities share a multi-renderer build, and its error message adds that easy-gl needs its own ../meta-gl; unlike the sharp-runtime message it names the develop branch but prints no git clone command. A plain SDL_RENDERER or VULKAN configure therefore never looks for easy-gl. The clone URL in the sharp-runtime message still names the older openeggbert organisation; for repositories that moved to libcna, GitHub redirects it. Branches, clone commands and the configure messages to grep for are on Building CNA: sibling checkouts and Debugging: configure failures.
sharp-runtime: the .NET vocabulary, once
A C++ reimplementation of XNA can either invent ad-hoc substitutes for byte, TimeSpan, events, IDisposable and Object.GetType() inside each ported file, or build the .NET-shaped foundation once as its own project. CNA's instruction file (CLAUDE.md) chooses the second: anything CNA needs from .NET (an alias, a class, an interface, an exception type) is added to sharp-runtime first, with the correct final name and namespace and only as much as CNA needs, and is never inlined into CNA headers as a raw C++ type.
At 41b918c9 sharp-runtime describes itself as a practical subset of System.* for native ports "without attempting to implement a CLR, JIT, garbage collector, or the complete .NET platform". Its scope has grown well past a minimal floor: its README lists collections, text, regular expressions, JSON, XML, streams, compression, networking and HTTP, tasks and channels, numerics and non-encryption cryptography, organised as independently selectable CMake components: the generated docs/ComponentCatalog.md at the same revision lists 47 registered components over 44 physical modules, plus the All aggregate (the README's own figure, 41, is out of date). CNA consumes a narrow closure of them through cmake/SharpRuntimeConsumption.cmake, which also detects whether the checkout is the modular or the older monolithic shape. Its porting status is tracked per .NET type in a SQLite database, plan.sqlite3, which is committed at that revision even though the repository's ignore rules also match it; the database lists 16,207 types, of which 1,087 are ported, 140 ignore and 14,980 ignored, with no rows left in an undecided state. Tutorial 89 walks through the library from a game's point of view.
easy-gl and meta-gl: OpenGL without a windowing opinion
The EasyGL family (three public identities sharing one CNA implementation factory) sits on easy-gl, whose defining choice is what it refuses to own. At deda7a42 its README says the host application owns window creation, GL context creation and activation, event processing, swap and present, and supplies a GetProcAddress callback; easy-gl owns everything below that: shaders and programs, buffers, vertex arrays, textures, framebuffers, draw calls and capability detection. Calling code gates features that exist only on desktop GL away from GL ES through easygl::Device::supports(Feature) and require(Feature). easy-gl itself adds ../meta-gl and links meta-gl::meta-gl, the typed function-loading layer beneath it, which likewise creates no window or context.
easy-gl's README calls its own scope a compact, evolving slice exercised by a hello-triangle-sdl example and two smoke-test targets (easy-gl-smoke-tests, easy-gl-resource-smoke-tests), although its tests/CMakeLists.txt registers four test executables (adding easy-gl-context-lifecycle-tests and easy-gl-webgl-tests); CNA's EasyGL renderer has grown far beyond that slice on top of it. In CNA the GL context comes from the SDL3 platform, whose video drivers cover the desktop window systems and the browser, which is how one easy-gl serves every host. See EasyGL internals and Tutorial 90.
xna4-spec and the representation census
A reimplementation drifts in two ways: between what its documents claim and what its code does, and between what it believes the original API was and what the original actually specified. xna4-spec was built against the second failure. At fedc17aa it holds 544 XML type files in 19 namespace directories (its README's summary line says 550 types, which the index file does not bear out), converted from Microsoft's XNA 4.0 reference pages, with members and their original descriptions; its stated purpose includes "auditing C++ reimplementations of XNA 4.0".
CNA's code, CMake and workflows do not reference xna4-spec at this snapshot. The census that produces 331/331 types and 3,627/3,627 members, tools/audit_xna_runtime_surface.py, reads Microsoft's own XML documentation and DLL metadata instead, and a transcription made from web pages is a weaker source than those. Use xna4-spec as a searchable offline inventory, with normalisation and an independent check before trusting a single row. The alpha.1 release notes quote a different, older measurement, 227 of 245 public FNA types present, whose denominator came from FNA's type list rather than from any Microsoft reference; it is a historical presence snapshot and not comparable with the census.
Two kinds of consumer proof
Two repositories exist to give CNA real code to run, and they answer different questions.
cna-samples ports Microsoft's XNA Game Studio 4.0 sample collection to C++ and is licensed Ms-PL to match its Microsoft-derived origin. Its question is does CNA run real, historical XNA code? At 5db32e6 (2026-10-03) its plan audits 153 entries, SAMPLE-001 to SAMPLE-153, drawn from the collection: 91 are marked complete (a native run plus a real-browser WebGL2 run, except three owner-scoped rows: one tool-only sample and two networking samples that are native-only), 8 relevant XNA 4.0 C# programs remain open (one of them the Racing Game, which has its own plan), and 54 entries are not port targets (older XNA versions, Silverlight, WinForms tools, VB.NET, C++, asset packs, platform services and duplicates). The samples gallery publishes 90 playable browser builds at b3939de, one of them marked as a partial release. Those are catalogue statuses for CNA's apple/m4-stabilization branch on that date, not results for this snapshot; the older explanation that samples were blocked by HLSL effects no longer holds (see Is it actually usable?).
cna-examples is original, MIT-licensed work (deliberately not a port of Microsoft material, so it can carry a permissive licence). Inspired by the JavaFX Ensemble sample browser, it is one cross-platform application in which a reader picks an area, then a category, then a demo. Its question is can every CNA area be shown working inside one program? At ea33c9a2 its README reports 13 areas, 79 categories and 249 demo screens, each calling real Microsoft::Xna::Framework or CNA::* APIs, rendered on both OPENGLES3 and SDL_RENDERER (the 3D area is gated off on the 2D-only renderer). Both repositories are evidence for the CNA revision they were built against.
Other repositories around CNA
Many more repositories surround CNA: a starter project (cna-template, whose lock file pins an older CNA), cna-extended (a C++ port of MonoGame.Extended on CNA), cna-lab (home of the CNA Craft port), the language bindings (cna-dotnet, the C# binding CNA.NET, is maintained and admits exactly C ABI 0.46.0, by CNA's record of cna-dotnet 8219a6c; eight bindings, for Common Lisp, Go, Java, Python, Ruby, Rust, Swift and TypeScript, are archived with their source and history in cna-lab under bindings/), and games built on the stack, such as mobile-eggbert, a C++ port of the 2013 Windows Phone Speedy Blupi on an early CNA revision. They are useful integration evidence, but each is evidence only for its own pinned revision and host, never for this snapshot by default. The site's showcase and demos list the public ones with their revisions.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- Internals
- EasyGL internals
- Maintainer workflow
- Change the build configuration
- Reference
- CMake option index
- Deep dives
- CNA and XNA 4.0 · Glossary