Experimental Native C API

CNA product 0.1.0-alpha.1  ·  declared C ABI 0.7.0  ·  source present, build blocked

The native C library is not consumable at the exact alpha.1 tag. Its headers, implementation, ABI metadata, examples, package rules and verification machinery are checked in, but the final C API implementation target fails a compile-time renderer-identity assertion: the C map has 49 entries while CNA has 50 public renderer identities. NanoVG is the missing C identity.

Tag status and scope

CNA_BUILD_C_API is an opt-in CMake option 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 tag contains 59 public C headers and 2,861 declared cna_* routes. Its checked-in route-name report accounts for all 2,861 declarations. Those facts describe the source surface; they do not prove that a library artifact was produced or that every route executes.

The alpha.1 compile blocker

The public C++ enum and generated registry contain 50 renderer identities. In modules/c-api/src/CnaCApiCoreExt.cpp, the RendererIdentities table contains 49 and the public C renderer enum ends at PIXIJS; there is no NanoVG entry. The same source deliberately checks the table against the canonical C++ count:

static_assert(RendererIdentities.size() == CanonicalRendererCount(),
              "A renderer was added to CNA::GraphicsRendererType without a C identity.");

For alpha.1 this assertion is false. An isolated GCC 14.2/Ninja build using Headless platform/renderer, Null audio and the default enabled networking reproduced the compiler diagnostic comparison reduces to (49 == 50). Consequently a configuration may create C API targets and the checked-in reports may look release-ready, but compiling the final native C API implementation cannot complete. Do not publish, install or bind to a self-described alpha.1 C API library without a source correction and a new compatibility decision.

Intended build and package design

The tag's CMake design says that enabling CNA_BUILD_C_API=ON turns on C as a project language, uses C17 for CNA's implementation targets, and checks the public headers against a C99 consumer surface. It also defines a CNACApi install component, a shared CNA::CApi target and an optional static CNA::CApiStatic target. These are intended interfaces, not successfully consumable alpha.1 artifacts.

After the renderer map is fixed in a later release, the declared standalone consumer shape is:

cmake_minimum_required(VERSION 3.20)
project(my_cna_game LANGUAGES C)

find_package(CNA 0.7 CONFIG REQUIRED)
add_executable(my_cna_game main.c)
target_link_libraries(my_cna_game PRIVATE CNA::CApi)

The declared install rules place public headers and CNA-built SDL libraries beside the shared API library; FFmpeg remains a system dependency when selected. None of those rules bypasses the alpha.1 compile assertion.

The C ABI version is not the product version

IdentityAlpha.1 valuePurpose
CNA product0.1.0-alpha.1Which CNA source release is documented.
Native C ABI0.7.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. Do not compare them with CNA_VERSION_*; the latter describe the C++ product build.

Programming model

ConcernC contract
ObjectsCNA_Handle values are opaque, typed and generation-checked. Release them in documented child-before-parent order.
FailuresFallible calls return CNA_Result; retrieve the recorded diagnostic rather than relying on C++ exceptions.
Strings/buffersQuery the required count, then copy into caller-owned storage. Buffer-too-small is a named result.
CallbacksGame lifecycle and events cross the boundary through function pointers and user-data values; thread and reentrancy rules are explicit.
CapabilitiesQuery the selected/active renderer and its capabilities; the C layer does not invent a second renderer-selection system.

The tag's modules/c-api/examples/c/hello_cna.c documents the intended use: it checks the ABI, creates a callback-driven game, borrows the graphics device only during a legal callback, queries capabilities, exercises diagnostics and shuts down in lifetime order. It is a design reference in alpha.1, not evidence of a runnable installed package.

Measured coverage

The checked-in alpha.1 inventory starts from 421 public C++ headers and 6,712 symbol rows: 6,317 are implemented in C, 15 are approved partial mappings, 380 are not applicable to a C consumer, and internal/detail rows are excluded separately. These numbers describe the checked-in generated inventory; they do not convert partial or not-applicable rows into full C++ parity.

The repository declares separate ABI-baseline, compatibility-matrix, coverage, limitations and release-gate workflows and contains installed-consumer test machinery. Their presence does not override the final source contradiction. In particular, the checked-in generated release report says ready while a workflow label says not ready and the final implementation cannot satisfy its own renderer-count assertion.

Important limitations

  • The final C library target is compile-blocked in alpha.1 by the 49-versus-50 renderer map.
  • CNA_BUILD_C_API=ON with CNA_ENABLE_NET=OFF is also broken: configuration succeeds, but the C API unconditionally includes GamerServices headers that are then absent. Keep networking enabled merely to reach the renderer assertion.
  • The declared ABI 0.7.0 is experimental and pre-1.0 even after those defects are corrected.
  • 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 checked-in rows are explicitly partial.
  • Thread, callback-borrow and shutdown rules are part of the intended contract. A numerically valid handle would not permit use on the wrong thread or after its owner shuts down.

Continue with Tutorial 129: Inspect the alpha.1 C API boundary, versioning, or the verification guide.