Experimental Native C API

CNA snapshot b0e97bb1  ·  product 0.1.0-alpha.1  ·  declared C ABI 0.44.0  ·  source present, gated, not built by any CNA CI workflow

⚠

Experimental and unreleased. This page documents the C API sources at CNA snapshot b0e97bb1 (branch next, still stamped 0.1.0-alpha.1). The ABI is pre-1.0 and its minor versions may break compatibility. No CNA CI workflow builds the C library; the strongest run evidence comes from the CNA.NET campaign, which built and used libcna_c_api on Linux from a CNA commit whose source is identical to this snapshot. CNA’s own release gate for the C ABI says “Not ready”, with 656 public C++ symbols still unmapped. Unless a sentence says otherwise, what follows was read from source, not built by us.

Snapshot status and scope

CNA_BUILD_C_API is an opt-in CMake option (default OFF) for a native C linkage layer under CNA/C/. At source level, that layer uses fixed-width values, versioned structures, opaque generation-checked handles, explicit result codes, count/copy string and buffer protocols, and callbacks instead of exposing C++ classes or STL types. The exported surface does not vary with configuration: a route whose backend is compiled out still exists and answers CNA_RESULT_NOT_SUPPORTED.

FactAlpha.1 tagThis snapshot
C ABI version0.7.00.44.0 (encoded 0x00002C00)
Public C headers5960 (adds cnb.h)
Declared cna_* routes2,8613,210 — the declared name set equals the recorded exported-symbol baseline set, with an empty difference in both directions
Recorded ABI baselinenot stated197 struct layouts, 295 scalar types, 1,466 integer constants, 14 string constants, 141 colour constants, 3,210 exports (tools/c-api/abi_baseline.json)
Semantic inventory6,712 rows (421 headers)8,142 symbols in 469 in-scope headers — see Measured coverage; the scope model changed, so the two are not directly comparable
Release gatereport and workflow disagreedNot ready: the committed report records 9 of 10 criteria met; the unmet one is 656 unmapped public symbols (not re-run for this page)
Built by CNA’s CI?nono — the five c-api-*.yml workflows are build-free (headers, JSON and Doxygen only)
Built and run anywhere?noyes, outside CNA’s CI: the CNA.NET campaign built libcna_c_api on Linux x86_64 from CNA commit 8a7e13ff5, which differs from this snapshot only in two documentation files, and ran its own test suites and the XNA samples against it

The first rows are facts about the source surface and its recorded metadata. The last row is evidence recorded by another project (CNA.NET’s campaign ledger, 4 October 2026), not by CNA’s CI and not by the authors of these pages. Treat the C library as a pre-release that you build and test yourself.

From the alpha.1 compile blocker to a built library

At the alpha.1 tag the library could not compile: RendererIdentities in modules/c-api/src/CnaCApiCoreExt.cpp held one row fewer than the canonical C++ renderer count, and the file deliberately checks the two against each other (an isolated GCC 14.2/Ninja build reproduced comparison reduces to (49 == 50); with networking off, configuration failed on a missing GamerServices include instead).

At this snapshot the table has 18 rows against 18 canonical identities, and the ceiling constant equals the highest published value. Both compile-time checks hold:

static_assert(RendererIdentities.size() == CanonicalRendererCount(),
              "A renderer was added to CNA::GraphicsRendererType without a C identity.");
static_assert(CNA_GRAPHICS_RENDERER_MAXIMUM == HighestPublishedIdentity(),
              "CNA_GRAPHICS_RENDERER_MAXIMUM must name the highest-valued published renderer "
              "identity.");

The networking trap is a deliberate configure-time error naming the option: CNA_BUILD_C_API=ON requires CNA_ENABLE_NET=ON, because the C API exports the GamerServices routes and links the GamerServices module unconditionally.

ℹ

How confident can you be? On Linux x86_64 the library is no longer only a source-level design: CNA.NET builds it with -DCNA_GRAPHICS_RENDERER=OPENGLES3 -DCNA_BUILD_C_API=ON -DCNA_EASYGL_COMPILED_EFFECTS=ON and its final regression run (CSX-153) records the native C API smoke programs and the managed integration suites passing against it. Android (NDK) and Emscripten builds of the library are used by CNA.NET’s Android-emulator and headless-Chromium hosts. Windows and macOS shared-library builds have not been run.

Build, package and consume

Enabling CNA_BUILD_C_API=ON turns on C as a project language, uses C17 for CNA’s implementation targets (with C extensions off inside modules/c-api, and -Wall -Wextra -Wpedantic -Werror there), and forces position-independent code. The public headers are held to a C99 consumer floor, checked against a matrix of language modes and toolchains (C99/C11/C17 and C++11/14/17 are required cells; 23 declared cells across 7 toolchains).

Setting or targetWhat it does
CNA_BUILD_C_APIOpt-in, default OFF. The three shipped CMakePresets.json presets that set it (dev, unit and release-modules) all set it OFF; no CI workflow enables it.
CNA_ENABLE_NETMust stay ON (its default) when the C API is enabled; otherwise a configure-time FATAL_ERROR.
cna_c_api / CNA::CApiThe shared library libcna_c_api.so (under Emscripten a static library that a host such as CNA.NET’s browser runtime links in). On ELF platforms a linker version script exports cna_* and nothing else; the symbol-version node is CNA_C_API_0.1 and is deliberately never bumped with minors.
CNA::CApiStatic / CNA_C_API_BUILD_STATICOptional static archive, default ON on Linux-like hosts with Python 3: the whole closure is partially linked into one relocatable object, every non-cna_* symbol is localized, and the build fails if any survives (except GCC’s STB_GNU_UNIQUE symbols). Linking it defines CNA_C_API_STATIC, which empties the export macro.
Install component CNACApiThe library, the public include/ tree, the SDL3 libraries CNA builds (installed beside the library; INSTALL_RPATH is $ORIGIN, so no LD_LIBRARY_PATH is needed), and the CMake package CNAConfig.cmake / CNAConfigVersion.cmake / CNACTargets.cmake under lib/cmake/CNA. FFmpeg is never shipped; it is a system dependency only when CNA_ENABLE_VIDEO selected it.
Package versionEqual to the C ABI version (read out of abi.h at configure time) with SameMajorVersion compatibility.
AndroidThe C API configures and builds with the Android NDK alone; the GamerServices service client and the online relay then refuse with CNA_RESULT_NOT_SUPPORTED.

The C++ framework itself still has no install() rules; only this C package is installable. To build and install just the C ABI from a source checkout of the next branch (with the sibling checkouts described in Building):

cmake -S . -B build -DCNA_BUILD_C_API=ON          # CNA_ENABLE_NET defaults to ON
cmake --build build --target cna_c_api
cmake --install build --component CNACApi --prefix /opt/cna

and, in a consumer project that has never heard of the CNA source tree, the shape CNA’s own example uses:

cmake_minimum_required(VERSION 3.20)
project(my_cna_game LANGUAGES C)

find_package(CNA 0.1 CONFIG REQUIRED)
add_executable(my_cna_game main.c)
set_target_properties(my_cna_game PROPERTIES C_STANDARD 99 C_STANDARD_REQUIRED ON C_EXTENSIONS OFF)
target_link_libraries(my_cna_game PRIVATE CNA::CApi)

Without CMake, the library is a plain shared object with C linkage: cc -std=c99 -I/opt/cna/include main.c -L/opt/cna/lib -lcna_c_api. See the CNA repository’s CONSUMING.md for the full consumption notes; where it says every minor within a major is additive, or that the device is legal only inside a callback, the version history and the threading section below are newer.

ℹ

Linux/ELF first. The consumer test CApi_InstalledConsumer installs the CNACApi component into a staging prefix, configures the hello_cna example as a standalone project against it, builds it shared and static, and runs both with no LD_LIBRARY_PATH. It is a local CTest registration (Linux/ELF only), not a CI job. The package machinery, RPATH, version script and consumer test are ELF/Linux only; Windows and macOS shared-library builds are not verified.

WebAssembly artifact

Under Emscripten the target cna_c_api_wasm emits an ES6 module (cna_c_api.mjs plus .wasm, createCnaCApi factory, ALLOW_MEMORY_GROWTH=1, ASYNCIFY=0) whose export list is generated from the headers by tools/c-api/generate_wasm_exports.py, and the static C archive can also be linked into another runtime’s WebAssembly module, as CNA.NET’s browser host does. Its ABI notes (by-value uint64_t arrives as BigInt, copied strings carry no NUL) are in CNA’s WASM_ARTIFACT.md. A browser host drives the game one frame at a time with cna_game_run_frame_ext from requestAnimationFrame; a threaded build (CNA_ENABLE_EMSCRIPTEN_THREADS=ON) can run the game thread as a browser worker. Three CTest registrations cover the module (CApi_WasmLinkContract, CApi_WasmModuleSmoke, CApi_WasmBrowserProbe); none runs in CI.

The C ABI version is not the product version

IdentityAlpha.1 valueThis snapshotPurpose
CNA product0.1.0-alpha.10.1.0-alpha.1 (unchanged; no newer tag exists)Which CNA source release is documented.
Native C ABI0.7.00.44.0Compatibility of the exported C binary contract.
#include <CNA/C/cna.h>

if (cna_get_abi_version() != CNA_ABI_VERSION) {
    return 1;
}

CNA_ABI_VERSION_MAJOR, _MINOR and _PATCH are fixed-width macros, encoded by CNA_ABI_VERSION_ENCODE as major<<16 | minor<<8 | patch. Do not compare them with CNA_VERSION_*; the latter describe the C++ product build. The exact-equality check above is the strictest and, while the ABI is 0.x, the safest one — it is also what CNA.NET does; CNA’s example accepts any equal-or-newer minor of the same major, which is a looser bet (see the next section).

ABI version policy and history

While the ABI is 0.x, an incompatible change requires a minor-version increment, release notes and a regenerated baseline; from 1.x on only additive changes are permitted within a major. ABI 1.0 is a separate decision the release gate explicitly does not make. CMake’s find_package(CNA 0.1 CONFIG) accepts any same-major version at or above the one requested, so CMake accepting the package is not a compatibility promise across 0.x minors: since alpha.1, 0.28.0 and 0.29.0 and the steps from 0.30.0 to 0.35.0 were incompatible, and 0.40.0 and 0.42.0 to 0.44.0 changed rules without changing exports. A program that must not break should compare the minor it was written against at run time, not only the major.

ABIWhat changed (CNA’s own summary)
0.1.0 – 0.6.0Initial ABI; additive routes; 0.3.0 was not additive (all 94 CNA_Bool-taking routes now refuse a byte outside 0/1); portable native-window handle routes (0.5.0); standardized empty-shader-source refusal (0.6.0).
0.7.0Six PBR / morph-target routes — the alpha.1 value.
0.8.0 – 0.9.0New renderer and capability identities (moved both MAXIMUM sentinels); owned-GraphicsDevice create/destroy, render-target ContentLost subscription; seven documented contracts changed in 0.9.0.
0.10.0 – 0.19.00.10–0.17: the .cnb container, document and asset schemas, the loader registry with .cnj/source compile front ends, and reflective content readers (eight additive generations). 0.18: a Dictionary<string,object> object-dictionary handle. 0.19: Load<Model> and the Tag a content processor wrote.
0.20.0 – 0.27.0Renderer-identity changes (0.20.0 incompatible, mostly reverted in 0.22.0); new device-type, 3D-texture-sampling, SPIR-V-dialect and base-instance identities (0.21–0.26).
0.28.0Incompatible. Renderer identity constants were retired; CNA_GRAPHICS_RENDERER_MAXIMUM moved, and every retired numeric value is permanently reserved.
0.29.0Incompatible. Removed the SpriteBatch 2D-mesh route (cna_sprite_batch_draw_mesh_ext) and its CNA_SpriteMeshEXT struct.
0.30.0 – 0.35.0Incompatible. The non-XNA graphics extension routes were reduced to the retro effects and debug drawing of graphics_ext.h (0.30.0); further renderer identity constants retired (0.31.0, 0.33.0); the Guide and GamerServices dispatcher follow the configured services and refuse unconfigured social and sign-in calls, with two picture-copy routes added (0.32.0); avatar extension routes and two Guide setters removed (0.33.0 and 0.34.0 on a parallel line); 0.35.0 merged both lines.
0.36.0 – 0.39.0Additive: cna_packet_reader_copy_data_ext (0.36); four queries for the canonical .NET exception type and parameter name behind a failure (0.37); cna_game_run_frame_ext, a host-driven run one frame at a time (0.38); cna_game_set_foreign_thread_calls_ext, an opt-in queue that runs other threads’ calls on the game thread (0.39).
0.40.0 – 0.44.0Rule changes plus one route: the graphics-adapter routes accept the game handle before its first callback (0.40); cna_game_run_foreign_thread_calls_ext lets a waiting game thread drain that queue (0.41); a game lends its device after creation and before its run begins (0.42); the two fire-and-forget sound-play routes answer on any thread (0.43); Activated/Deactivated handlers may use the device (0.44.0, this snapshot).

The full table lives in CNA’s ABI_VERSIONING.md. The recorded baseline is enforced by a generator (generate_abi_baseline.py, registered as the CTest gates CApiAbiHeaderBaseline and, where a library exists, CApiAbiBaseline).

Renderer identity values

CNA_GraphicsRendererType is a stable, sparse integer identity: a renderer’s value never changes and a reserved value is never reused, so the numbers from CNA_GRAPHICS_RENDERER_UNKNOWN (0) to CNA_GRAPHICS_RENDERER_MAXIMUM (currently 43, FNA3D) contain gaps. The 18 identities keep fixed values (for example CNA_GRAPHICS_RENDERER_VULKAN is 8), and every route that takes an identity refuses a reserved value or anything above MAXIMUM with CNA_RESULT_INVALID_ARGUMENT. Because some reserved values lie above the current maximum, the next new identity will take 52, not MAXIMUM + 1. scripts/check_renderer_identities.py fails the build if a reserved value is reused.

An identity is not a support claim. Two builds carrying the same identity can answer capability queries differently, so branch on cna_graphics_device_supports_capability and the renderer-feature queries, never on the renderer name or number. The list of identities and what each one supports is on the Renderers page.

Programming model

ConcernC contract
ObjectsCNA_Handle (uint64_t, CNA_INVALID_HANDLE = 0) values are opaque, typed and generation-checked: slot in the low 32 bits, generation in the high 32. A zero, stale, wrong-kind or foreign handle answers CNA_RESULT_INVALID_HANDLE. Release owned handles child-before-parent; cna_game_destroy answers CNA_RESULT_INVALID_STATE while an owned graphics child is alive. One active game per process.
FailuresFallible calls return CNA_Result (0 success … 14 buffer too small); no C++ exception crosses the ABI. The failing thread keeps a diagnostic: cna_error_get_last_info, cna_error_get_last_message_size, cna_error_copy_last_message. The query routes never overwrite it.
BooleansCNA_Bool is uint8_t; only 0 and 1 are valid and every route taking one refuses other bytes with CNA_RESULT_INVALID_ARGUMENT.
Strings/buffersUTF-8 CNA_StringView { data, byte_length } in; count-then-copy out. The count excludes any terminator, and a too-small buffer is refused with CNA_RESULT_BUFFER_TOO_SMALL and no partial write.
Versioned structsExtensible inputs start with struct_size and struct_version; zero the struct, set both, and CNA reads only the fields your size says you know.
CallbacksGame lifecycle and events cross the boundary through function pointers and user-data values. Callbacks run synchronously on the game’s thread with borrowed handles; returning a failure stops the game and the enclosing call reports CNA_RESULT_CALLBACK. Never throw or longjmp out of one.
ThreadingLifecycle, game, graphics, content, input, media, device and resource-destruction calls belong to the runtime’s creation thread; a wrong-thread call answers CNA_RESULT_THREAD unless one of the opt-in rules in Threads, frames and host-driven runs applies.
CapabilitiesQuery the selected/active renderer and its capabilities; the C layer does not invent a second renderer-selection system. The renderer-capability profile is reachable through cna_graphics_device_get_renderer_feature_support_ext, _get_renderer_limit_ext, _get_surface_format_support_ext and the count-then-copy capability report (_get_capability_report_size_ext, _copy_capability_report_ext).

The shipped example modules/c-api/examples/c/hello_cna.c (354 lines) is the reference: it checks the ABI, creates a callback-driven game, borrows the graphics device only during a legal callback, queries capabilities, exercises count-then-copy, provokes and reads two deliberate errors, creates and draws a texture, and shuts down in lifetime order. It is guarded so that it exits cleanly with no display.

Threads, frames and host-driven runs

By default every lifecycle, game, graphics, content, input, media, device and resource-destruction call belongs to the runtime’s creation thread, and a call from another thread answers CNA_RESULT_THREAD. The ABI generations since 0.36 add controlled exceptions to that rule, each opt-in or narrowly scoped:

NeedRoute or ruleSince
Drive the game from a host loop (a browser’s requestAnimationFrame, an editor)cna_game_run_frame_ext(game, &running) once per frame. The first call initializes and delivers begin_run; the call that finds the game exited delivers exiting and then end_run. The C++ equivalent is Game::RunFrameEXT.0.38
Call CNA from a worker threadAfter cna_game_set_foreign_thread_calls_ext, a call refused only for coming from another thread is queued: the caller blocks, the game thread runs it at the start of its next update or draw (up to 8 ms per step) and returns the result and error record. Driving or destroying the game is still refused; turning the feature off fails pending calls with CNA_RESULT_INVALID_STATE.0.39
Wait for such a worker inside a callbackcna_game_run_foreign_thread_calls_ext drains the queue while the game thread waits. A game thread that waits for a worker without draining deadlocks.0.41
Use the graphics device outside a callbackThe device is lent between cna_game_create and the start of the run, on the creating thread (0.42), and inside Activated/Deactivated handlers (0.44); between frames it is still refused.0.42, 0.44
Play a sound from any threadcna_sound_effect_play and cna_sound_effect_play_with_settings only; other audio routes keep the thread check.0.43
Read the adapters earlyThe cna_graphics_adapter_* routes accept the game handle before the first callback.0.40
Know which .NET exception a failure meansFour queries return the canonical exception type and parameter name behind the last failure (failures the C layer raises itself name none).0.37

CNA.NET is the main consumer of these routes: its browser host uses the host-driven run, and XNA games that start threads use the foreign-thread queue. CNA’s own CALLBACKS_AND_THREADING.md predates them; the header comments in runtime.h are authoritative.

Route families and the largest headers

The 60 headers under modules/c-api/include/CNA/C/ carry extern "C" guards, except the umbrella CNA/C/cna.h (which only includes the others) and the constants-only named_colors.h. The largest, by declared routes (lines starting CNA_C_API):

HeaderRoutesWhat it carries
effects.h290Effects: BasicEffect, skinned, environment-map and PBR effects, custom shader effects, plus effect parameters, techniques and annotations.
cnb.h new272CNA’s .cnb compiled-content container: identities, byte-level constants, checksums, whole-file arithmetic, read limits and chunk compression (per the header’s own description). See CNB Format.
gamer_services.h239GamerServices: signed-in gamers and their property dictionaries, achievements, leaderboards, the Guide and the Avatar renderer and animations.
models.h216Models: meshes, bones, skinned models and skinning data, the animation player and morph targets.
media_library.h148The XNA media library: picture albums and collections, albums, artists, genres and playlists.
sensors.h144Sensor readings: accelerometer, gyroscope, compass, motion and attitude.
vectors.h137Vector2/3/4 value types: accessors, initializers and transforms.
net_sessions.h104NetworkSession: creation, find and join, gamers, properties and the session lifecycle.

The opt-in CNAEXT extensions (retro effects and debug drawing) have 44 routes in graphics_ext.h. Not in the C ABI at all: Diagnostics and the Inspector have no C routes, and the build-time Content Pipeline, the Windows-Phone shell module, the platform substrate and the renderer implementations are out of runtime C scope by owner decision (see Measured coverage).

Your first C program

Tutorial 129 walks through a complete first program against ABI 0.44.0: install the CNACApi component, find_package(CNA 0.1 CONFIG REQUIRED), link CNA::CApi at C99, check the ABI, create a game with callbacks, borrow the graphics device, read the renderer name with count-then-copy, print the error diagnostic, and tear down children before the game. The tutorial is honest about the same caveat as this page: no CNA CI job builds the library, and the docs’ authors did not build it.

Measured coverage

CNA’s generated inventory (COVERAGE.md, produced by tools/c-api/generate_coverage_inventory.py) derives the complete public C++ declaration list from modules/*/include and maps every symbol through coverage_mappings.json. At this snapshot it reports 469 headers in scope, 8,142 symbols: 7,030 implemented in C, 15 approved partial mappings, 656 planned (not yet mapped) and 441 not applicable to a C consumer; 471 headers are explicitly excluded. The planned rows sit mostly in graphics (275) and content (206). These numbers describe the checked-in generated inventory; they do not convert partial or not-applicable rows into full C++ parity.

ℹ

Not comparable with alpha.1’s inventory. The alpha.1 inventory started from 421 headers and 6,712 rows (6,317 implemented, 15 partial, 380 not applicable). The scope model has since changed: the build-time Content Pipeline (107 headers), the Windows-Phone shell module (9), the platform substrate (27), renderer implementations (138) and every Internal/Detail path are now classified as out of runtime C scope by recorded owner decisions. Read the new figures as a snapshot of the current model, not as growth from 6,712.

The 656 planned rows are the live backlog and the reason the committed release-gate report reads Not ready. CNA’s own coverage audit says an earlier “about 3,000 planned” figure was mostly mis-modelled evidence and that the genuinely missing runtime bindings measured 259 logical APIs before the scanner was repaired.

Gates and CI: what is actually checked

The C ABI has a large gate suite, but almost all of it is header-, JSON- or documentation-level. Nothing in it compiles the library.

MechanismWhere it runsWhat it proves
c-api-abi-baseline.yml, c-api-compat-matrix.yml, c-api-coverage-gate.yml, c-api-limitations.yml, c-api-release-gate.ymlGitHub Actions, ubuntu-24.04, automatic on push/PR to next, develop, main (path-filtered) plus manual dispatchRecorded layouts and constants; every public header compiles alone and through the umbrella in the declared language modes; the coverage inventory; the limitations report; the release verdict. Build-free.
12 header/JSON gate tests in ModuleProbes.cmake (CApiAbiHeaderBaseline, CApiDeclaredExports, CApiReleaseGate, …)Ordinary CNA build (deliberately not inside if(CNA_BUILD_C_API))The same facts, checkable without building the C library.
93 pure-C programs, 4 C++ tests, 1 libFuzzer source (104 registered tests)Only where a developer configures -DCNA_BUILD_C_API=ONRoute behaviour, handle lifetime, boolean contract, threading and UTF-8 oracles. Not GoogleTest; they are not part of the site’s test-definition counts.
CApi_InstalledConsumerLocal CTest, Linux/ELF, timeout 900 sInstall, find_package, build hello_cna shared and static, run both.
Route test coverage ratchetOrdinary buildEvery exported route is named by at least one test or example source (budget of uncovered routes: 0).

The CNA.NET campaign’s final regression run on Linux x86_64 (CSX-153, 4 October 2026) records the native C API test set passing on a library built from source identical to this snapshot. We did not reproduce it; the definitive check for your toolchain is one out-of-source build of -DCNA_BUILD_C_API=ON followed by ctest -R '^CApi'.

Language bindings: maintained and archived

CNA is implemented in C++23, and this experimental C ABI is the one foundation every other language builds on. C++ is CNA’s native implementation language, not a binding. CNA actively maintains two language bindings: C, which is this ABI itself, and C#, through CNA.NET. Eight further bindings — Common Lisp, Go, Java, Python, Ruby, Rust, Swift and TypeScript — were developed during CNA’s history and are now archived.

CNA publishes one experimental C ABI and generates no language bindings. CNA’s own plan lists “a language-specific binding, wrapper, package, generator or sample for any language other than C” as a non-goal inside the CNA repository; every other binding is a separate project that consumes this ABI.

⚠

Pair versions exactly. While the ABI is 0.x, a minor version may break compatibility, so each binding admits the ABI generations it was qualified against and refuses the rest. CNA.NET at revision 860f92c admits exactly 0.44.0, the version this snapshot exports; the archived bindings admit older generations only.

Maintained bindings: C and C#

Binding (revision, date)StatusABI admittedWhat it is
C: CNA’s own CNA/C/ headers and cna_c_api library, b0e97bb1, 2026-10-04experimental; release gate “Not ready”0.44.0The ABI itself: see Snapshot status and scope. Tutorial 129 is a first program, and cna-multi-language-3d-demo contains a complete small 3D game written in C99 against it.
cna-cs (C#/.NET, “CNA.NET”) 860f92c, 2026-10-04beta, source-first; no published packagesexactly 0.44.0A thin managed layer over the C ABI: CNA.Interop (P/Invoke), CNA.Framework (idiomatic API) and CNA.XnaCompat, a Microsoft.Xna.Framework-compatible facade that runs XNA 4.0 C# source. See C# with CNA.NET.

Archived bindings: Common Lisp, Go, Java, Python, Ruby, Rust, Swift and TypeScript

🗃

Archived — not maintained. These eight bindings are a real part of CNA’s history, not throwaway experiments: several were taken far, with large test suites, templates and measured coverage of the XNA 4.0 runtime surface. They were archived because keeping each of them current against a C ABI that changes quickly before 1.0 cost more time than the project could give them; that effort now goes into C++, the C ABI and C#. They do not follow new ABI versions. Their source code, templates and full Git history are kept in CNA Lab (libcna/cna-lab, under bindings/), and if there is real community interest in a particular binding, its status can be reconsidered.

Seven of them (Go, Java, Python, Ruby, Rust, Swift and TypeScript) were requalified on Linux against C ABI 0.35.0 on 30 September 2026, immediately before they were archived; Common Lisp stopped earlier, on 8 September 2026. Each row describes the binding at its final revision.

Archived binding (final revision, date)Status in its own wordsABI admitted
cna-common-lisp (Common Lisp, SBCL) c09a758, 2026-09-08projects “a selected subset” of XNA 4.0; qualified on SBCL on Linux x86-640.21.0 to 0.23.0
cna-go (Go, cgo) 9e46194, 2026-09-30256 of the 257 selected types projected completely0.35 or later (qualified against 0.35.0 only)
cna-java (Java 17, JNI) c2227a1, 2026-09-30“early, measured Java 17 projection”; the runtime surface structurally at zero diagnostics. A small Kotlin layer over it is kept beside it.exactly 0.35
cna-python (Python, ctypes) 36242c7, 2026-09-30“pre-alpha, measured Python projection”exactly 0.35
cna-ruby (Ruby, Fiddle) 25624a9, 2026-09-30257 of 257 selected types and 2,915 of 2,915 membersexactly 0.35.0
cna-rust (Rust) 377af7e, 2026-09-30“early, measurable safe Rust projection”; selected profile structurally completeexactly 0.35
cna-swift (Swift 6, Linux) 8fc3c29, 2026-09-30“real Swift projection”; 257 selected types strict-complete0.35 or later (qualified against 0.35.0 only)
cna-ts (TypeScript and JavaScript; Node-API and WebAssembly) 80514a5, 2026-09-30“the complete XNA 4.0 runtime surface is projected and verified”; ran in headless Chromiumexactly 0.35

These rows are evidence for each repository’s own final revision, not for CNA at this snapshot: none of the eight admits ABI 0.44.0 as qualified. If you write your own consumer, the stable markers CNA publishes are: cna_get_abi_version() (encoded 0x00002C00 for 0.44.0), the CNA_ABI_VERSION macro, the CMake package version, the ELF symbol-version node CNA_C_API_0.1, the machine-readable tools/c-api/abi_baseline.json (every struct layout, constant and export), the export/declaration set-difference gate check_declared_exports.py, and the per-artifact manifest from generate_artifact_manifest.py.

Important limitations

  • No CNA CI job builds the C library. Run evidence comes from the CNA.NET campaign (Linux x86_64, plus Android-emulator and headless-Chromium hosts), not from CNA’s CI and not from us.
  • The release gate reads Not ready: 656 public C++ symbols are still unmapped, and 441 more are recorded as having no C form (see CNA’s LIMITATIONS.md).
  • The declared ABI 0.44.0 is experimental and pre-1.0. Several minor steps since alpha.1 were incompatible and more may follow; ABI 1.0 is a separate future decision.
  • Package machinery, RPATH, the version script and the consumer test are Linux/ELF-only; Windows, macOS and iOS shared-library consumption is not verified.
  • Platform substrate interfaces that a C++ implementation would subclass are intentionally not exposed for C callers to implement.
  • Some C++ overloads, containers and polymorphic values map to narrower typed routes or snapshots; 15 rows are explicitly partial.
  • Thread, callback-borrow and shutdown rules are part of the contract. A numerically valid handle does not permit use on the wrong thread or after its owner shuts down; the cross-thread routes are opt-in and keep their own limits.
  • CNA.NET is a separate beta project that pairs with exactly one ABI version, and the eight archived bindings are not updated at all; see Language bindings.

Continue with Tutorial 129: Your first C program against ABI 0.44.0, C# with CNA.NET, versioning, or the verification guide.