Tutorial 129: Inspect the Experimental C API Boundary
Do not attempt to ship the alpha.1 C library. Product release 0.1.0-alpha.1 contains a broad C ABI 0.7.0 source surface, but its final C API implementation cannot compile: the C renderer table has 49 entries while CNA has 50 identities. NanoVG has no C identity.
Confirm the tag-level blocker
Inspect modules/c-api/src/CnaCApiCoreExt.cpp. Its RendererIdentities array ends at PIXIJS, has 49 rows, and is checked against the generated canonical C++ renderer count:
static_assert(RendererIdentities.size() == CanonicalRendererCount(),
"A renderer was added to CNA::GraphicsRendererType without a C identity.");
The tag's C++ enum includes NanoVG as identity 50, so the assertion fails. An isolated Headless/Null-audio build with default networking reproduces comparison reduces to (49 == 50). This is a useful fail-closed guard: the C contract cannot silently return the wrong identity. It also means the later configure, install and consumer steps in the repository describe an intended design, not a usable alpha.1 package.
Do not try to avoid the issue with -DCNA_ENABLE_NET=OFF. Alpha.1 configures that combination but then fails earlier because the C API unconditionally includes a GamerServices header whose module is disabled.
Understand the intended consumer project
After a later release corrects the renderer map, the declared package shape is a C99-compatible public header surface backed by C17 implementation targets:
cmake_minimum_required(VERSION 3.20)
project(hello_cna_c LANGUAGES C)
find_package(CNA 0.7 CONFIG REQUIRED)
add_executable(hello_cna main.c)
set_target_properties(hello_cna PROPERTIES
C_STANDARD 99
C_STANDARD_REQUIRED ON
C_EXTENSIONS OFF)
target_link_libraries(hello_cna PRIVATE CNA::CApi)
Read the source-owned example
The following excerpt shows the intended API style. It is documentation only at alpha.1; you cannot link it against a successfully built tag artifact.
#include <CNA/C/cna.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
static CNA_Result update(
CNA_Handle game,
const CNA_GameTime* time,
void* context,
CNA_CallbackError* error)
{
(void)time;
(void)context;
(void)error;
return cna_game_request_exit(game);
}
int main(void)
{
const uint32_t abi = cna_get_abi_version();
if ((abi >> 16U) != CNA_ABI_VERSION_MAJOR) {
fprintf(stderr, "incompatible CNA C ABI\n");
return 1;
}
CNA_GameCallbacks callbacks;
CNA_GameCreateInfo create_info;
CNA_Handle game = CNA_INVALID_HANDLE;
static const char title[] = "CNA C API";
memset(&callbacks, 0, sizeof(callbacks));
callbacks.struct_size = (uint32_t)sizeof(callbacks);
callbacks.struct_version = UINT32_C(1);
callbacks.update = update;
memset(&create_info, 0, sizeof(create_info));
create_info.struct_size = (uint32_t)sizeof(create_info);
create_info.struct_version = UINT32_C(1);
create_info.is_fixed_time_step = CNA_TRUE;
create_info.target_elapsed_time_ticks = INT64_C(166667);
create_info.window_title.data = title;
create_info.window_title.byte_length = sizeof(title) - 1U;
create_info.callbacks = &callbacks;
CNA_Result result = cna_game_create(&create_info, &game);
if (result == CNA_RESULT_SUCCESS) {
result = cna_game_run(game);
}
if (game != CNA_INVALID_HANDLE) {
CNA_Result destroy_result = cna_game_destroy(game);
if (result == CNA_RESULT_SUCCESS) result = destroy_result;
}
return result == CNA_RESULT_SUCCESS ? 0 : 1;
}
Every fallible operation returns CNA_Result. Versioned structures must be zero-initialized and must set struct_size plus struct_version. Handles are opaque, generation-checked and thread-affine; owned child objects must be destroyed before their owning game.
What to require from a later release
- The native library compiles with all 50 renderer identities mapped, or the public identity set is intentionally versioned.
- An installed consumer builds against the staged
CNACApipackage in both claimed shared/static modes. cna_get_abi_version()matches the publicCNA_ABI_VERSIONpolicy.- Runtime vertical slices execute for every configuration the release claims, with structured failures and ownership rules checked.
The complete source-owned example at modules/c-api/examples/c/hello_cna.c remains useful for reviewing capability queries, count-then-copy strings, resource ownership and diagnostics, but it is not alpha.1 runtime evidence.
What is still measurable: the tag contains 59 public C headers and 2,861 declared route names; its checked-in inventory records 6,317 implemented, 15 partial and 380 not-applicable rows out of 6,712. These are source and generated-report counts, not proof of a linkable or runnable C library.