Skip to content
The CNA BibleCNA 0.1.0-alpha.1 Edition

Chapter 11 Dependencies, Tests, Examples, and Developer Tools

A successful CNA configure can involve checked-out submodules, sibling repositories, system packages, downloaded source, prebuilt binary releases, and renderer-specific SDKs. Treating all of them as “vendored dependencies” hides the most common reproducibility failures. This chapter maps the acquisition mechanisms and the developer surfaces that consume them; Chapter 4 owns the command-line configuration details.

11.1 Five acquisition mechanisms

Mechanism Representative inputs Reproducibility boundary
Git submodules GoogleTest, SDL3, SDL3_image, SDL3_mixer A source archive may omit them; initialize the recorded submodule commits before configuring.
In-tree sources cgltf, stb, ENet, and a wgpu-native vendor area Present in the CNA tree, but build/features still depend on the selected module and host.
Sibling checkouts sharp-runtime, easy-gl/meta-gl, free-direct/free-api Separate repositories with their own pins and sometimes fixed sibling-relative paths.
Fetch/download or external artifact bgfx, Blend2D, Diligent, FNA3D, LLGL, Magnum, OpenVG, PortableGL, sokol, WebGPU, Wicked, Skia Each renderer has a distinct pin, offline override, patch, or prebuilt-root contract.
System packages FFmpeg, optional Draco, Vulkan/OpenGL/GLES libraries, Threads Host package discovery can change which files compile or whether configure is admissible.

The categories can compose. FNA3D is fetched from a pin and carries MojoShader through its own submodules. EasyGL is a sibling checkout that itself expects meta-gl as a sibling. Free-direct is a sibling that PUBLIC-links the second-level free-api sibling. A lockfile for only CNA’s own git tree is therefore not a complete build identity.

11.2 Submodules: initialize, do not guess

CNA’s considered instruction is git submodule update --init, not a recursive update. The optional codec trees beneath SDL are disabled by CNA’s vendored-SDL configuration, so recursive initialization adds time without contributing compiled inputs. The configure guards explain when the four required submodule directories are missing and explicitly note that a plain source archive cannot manufacture their content.

For a distributable source snapshot, either include those exact submodule trees or select a supported system-SDL path and provide GoogleTest another documented way. Silently building against whatever SDL happens to be installed changes the dependency claim.

11.3 The unusual SDL configure-time build

The controlling option is CNA_USE_SYSTEM_SDL. With the default vendored path, CMake configures, builds, and installs SDL3, SDL3_image, and SDL3_mixer during CNA’s configure step. The install prefix is persistent and outside the individual build directory, then consumed through the packages’ exported CMake configs.

This has three operational consequences:

  • deleting or cleaning a CNA build directory does not necessarily rebuild SDL;

  • the prefix is keyed by target system and processor so a cross-build does not overwrite a native installation;

  • a configure failure may actually be a nested dependency compile/install failure, not a CNA CMake-language error.

The default parallelism ceiling is intentionally small. Image and mixer codec options are pruned: for example, the vendored SDL_mixer build does not enable the optional MP3, Opus, FluidSynth, WavPack, or FLAC dependency families. CNA’s higher-level Audio and Media behavior must be read against that concrete mixer build, not against every feature SDL_mixer can support in principle.

11.4 System-package gates can change source composition

FFmpeg illustrates why “dependency found” is not merely a link flag. CNA computes the CNA_FFMPEG_AVAILABLE flag. On Windows/MinGW, Emscripten, and Android it is forced off so a cross-configure cannot accidentally import the host’s native pkg-config headers and libraries. When off, the Media module drops its video decoder/player translation units, Content drops the XNB video reader, and the unit-test source set excludes matching cases.

Draco is optional in a different way. Its absence does not remove the glTF importer; a Draco-compressed primitive reaches a named unsupported-format failure. Vulkan and several GL-based renderers, by contrast, require their native SDK/package at configure time. These are three different states: feature source omitted, format rejected at runtime, and configuration refused.

11.5 Sibling repositories are part of the workspace contract

sharp-runtime is always required. CNA_SHARP_RUNTIME_ROOT defaults to ../sharp-runtime, and CNA emits a fatal diagnostic explaining that it is not a submodule. The consumption adapter detects the current component-target shape and links each CNA module to a declared sharp-runtime component closure; it can also recognize the older monolithic target shape. For this edition, only the revisions in Appendix D are authoritative.

CNA’s alpha.1 release verification additionally records sharp-runtime 625476d5b5fff5fa89f392c3c9af8638ff237692. That is release evidence, not a CMake-enforced dependency lock: CNA_SHARP_RUNTIME_ROOT still accepts the caller’s checkout and CNA does not compare its Git SHA. This Bible retains its deeper sharp-runtime technical pin f827a6c5 for chapters auditing that sibling; Appendix D keeps the two roles explicit rather than arbitrarily repinning the sibling book scope.

EasyGL’s five public identities expect ../easy-gl; easy-gl then expects ../meta-gl. CNA exposes no override for those two relative paths. FREEDIRECT similarly expects the free-direct sibling checkout, which resolves free-api itself and reuses CNA’s already-created SDL targets. A CI checkout that clones only CNA can therefore configure some renderer identities but not others.

Do not paper over this by copying sibling sources into CNA’s build tree. Their independent commit, tests, public targets, and consumer evidence are part of the claim.

11.6 Renderer dependencies are intentionally asymmetric

Some renderer integrations fetch a pinned source tree automatically; some prefer a supplied root; some require a prebuilt external product. Examples at the pin include:

  • WEBGPU auto-downloads a pinned wgpu-native binary release unless an explicit root is given;

  • WICKED has a pinned commit and patch set but auto-fetch is off by default;

  • SKIA is never fetched and requires caller-supplied prebuilt directories;

  • MAGNUM first tries system Corrade/Magnum packages, then falls back to pinned source;

  • BGFX applies an in-tree patch during its fetched-source preparation;

  • OPENVG and several Sokol modes still require a real OpenGL system package.

Accordingly, “all renderer identities accepted by CMake” is not “all renderer dependencies are available on this host.” Chapter 20 separates identity, family, internal native sub-selector, and platform admission.

11.7 Build-tree C++ consumption and the native C package

The C++ framework remains primarily a build-tree/subdirectory product: a parent project adds the checkout or follows a sibling template, and the module targets compose into its final consumer. Alpha.1’s optional native C API source defines a deliberately narrower install surface. Its CMake rules would install the shared CNA::CApi target, C headers, CNAConfig.cmake, and a package-version file; suitable Unix builds also define CNA::CApiStatic. The external hello_cna.c gate is designed to configure through find_package(CNA CONFIG), link the installed target, and run it. These are source-proven packaging routes, not a successful alpha.1 artifact: the exact tag cannot compile cna_c_api because its C renderer table omits NanoVG. Appendix I records the reproduced failure.

The intended package’s version is the native C ABI version, not the CNA product SemVer. It does not turn all C++ module archives into a general installed C++ SDK, nor does it erase the sibling-resolution contract of source-tree builds.

Likewise, CNA is a CMake target, while CNA::Math and other namespaced aliases are module targets. Neither spelling implies a file named libCNA.so; most framework pieces are static archives composed into the final consumer.

11.8 The CnaTests corpus

The main GoogleTest executable is assembled from module-owned test sources plus the selected renderer configuration. Feature gates, platform exclusions, renderer selection, and optional FFmpeg/Net inputs change its compiled definition population. There is no configuration-free “number of CNA tests.” Chapter 68 explains composition, and Chapter 69 derives the pinned static populations without exchanging files, macros, CTest registrations, and executed cases.

The native tests preset deliberately says to run CnaTests directly. CTest’s GoogleTest discovery can launch each case as a short-lived process, while this repository includes display-dependent binaries and fixtures sharing fixed temporary paths. CTest remains useful for named standalone gates and renderer executables; it is not automatically the authoritative runner for the monolithic corpus.

11.9 Examples are executable documentation, not one evidence tier

Module-local examples range from tutorial programs to GPU readback tests, golden-image comparisons, host/browser harnesses, and policy-only probes. The filename or registration directory does not tell which one it is. For each example record:

  • whether it is compiled by the selected configuration;

  • whether it runs automatically or only by explicit dispatch;

  • which renderer/native driver/host actually engaged;

  • whether its oracle is exit status, structured values, pixels, or human inspection;

  • which unavailable-host outcome is skip, refusal, or failure.

Shared golden images remain at repository level because many renderer modules consume the same oracle. A renderer-owned test executable plus a shared image is still two artifacts whose provenance and update rules must travel together.

11.10 Presets are named environments, not universal promises

The pinned presets cover a Web build, three Devices sanitizer builds, and a native Ninja test build. The sanitizer presets pass raw compiler/linker flags even though CNA also exposes the CNA_SANITIZE option; this is redundant but observable. They explicitly enable CNA_DEVICES, preventing a sanitizer job named for Devices from silently compiling the feature out.

A preset proves only its declared target and commands. The Web preset builds the house demo with tests off; it is not a browser conformance run. The native test preset builds CnaTests; it does not make every standalone CTest executable. Hosted workflow reality is audited separately in Chapter 73.

11.11 Developer tools and what they decide

CNA’s mechanical tools fall into distinct authority classes:

Structural validators

Compare finite source-owned sets, paths, and identity spellings. They are strong for structural equality and silent about behavior.

Module probes and closure checkers

Compile a minimal consumer or inspect a link artifact. Their verdict depends on generator and host engagement, as Chapter 10 shows.

Content and catalog checkers

Validate CNJ/glTF fixtures, examples, or documented catalogs. Their parser and denominator define the result.

Renderer/golden harnesses

Exercise a chosen native path and compare pixels or structured output. They require identity and driver evidence in addition to a green comparison.

Cross/toolchain launchers

Stage DLLs, select Wine prefixes, start browsers, or prepare target files. Successful process creation is not yet proof that the intended runtime did the work.

The durable rule is to keep acquisition, build, registration, execution, and oracle engagement as separate facts. A dependency pin enables reproducibility; it does not establish that a test used the dependency. A built example establishes reachability; it does not establish correct pixels. Appendix G provides the compact claim vocabulary used throughout the rest of the book.

Type at least three characters. Results are ranked by how often and where the words occur.