Tutorial 127: Choose Platform, Renderer, and Audio Independently
Core idea: this snapshot has four different axes — target operating system, host platform implementation, graphics renderer, and audio implementation — plus one switch that decides whether SDL is configured at all (CNA_ENABLE_SDL). “Backend” is too ambiguous to stand in for any of them.
The three CMake selections (and one switch)
| Variable | Implemented values | Default |
|---|---|---|
CNA_PLATFORM | SDL3, X11, WAYLAND, WIN32, HEADLESS, TERMINAL — six, but WIN32 is offered only for Windows targets, TERMINAL only off Windows, and X11/WAYLAND only when their development packages are found | SDL3 on every OS |
CNA_GRAPHICS_RENDERER | One of 18 public identities | OS-dependent: Emscripten WEBGL2, Linux OPENGLES3, everything else SDL_RENDERER |
CNA_AUDIO_PLATFORM | SDL3, NULL, ALSA (Linux targets only) | SDL3 on every OS |
CNA_ENABLE_SDL (switch) | AUTO, ON, OFF (also TRUE/1 and FALSE/0/NO) | AUTO |
CNA_PLATFORM owns window, events, input, timing and host services. The renderer produces pixels. CNA_AUDIO_PLATFORM chooses the audio-device integration boundary. CNA_ENABLE_SDL decides whether the vendored SDL3 sub-build runs: with AUTO or ON SDL is configured as it always was; with OFF it is not fetched, built, found or linked, and any selection that genuinely needs it is refused by name. The compiler/toolchain still decides Linux, Windows, macOS, Emscripten, Android or iOS separately. Platform and audio values are case-sensitive; CNA_ENABLE_SDL is normalised.
Three of the six platforms are native backends that contain no SDL at all — X11 (Xlib, XKB, XInput2, XRandR, GLX), WAYLAND (a direct Wayland client) and WIN32 (user32, gdi32, WGL). They are described in Native Platforms (X11, Wayland, Win32). There is no CNA_PLATFORM environment variable: one implementation is the compiled default, and the always-compiled Headless (and, off Windows, Terminal) can additionally be created by name at run time through PlatformFactory.
The three audio choices do not offer the same XNA feature set. SOUND_ENABLED is defined for SDL3 and ALSA. SDL3 uses SDL3_mixer; ALSA uses CNA’s own mixer and no SDL. NULL provides a real low-level IAudioDevice implementation, but that build omits the high-level mixer engine, so SoundEffect playback, MediaPlayer, XACT audibility and Microphone are not available. Choose NULL for silent CI, servers and device-boundary work, not as a drop-in production playback replacement. The Audio reference has the full matrix.
Combinations CMake refuses
The axes are independent, with hard exclusions. Every refusal is a configure-time FATAL_ERROR that names the reason; nothing silently falls back to SDL3.
| Selection | Why it is refused |
|---|---|
CNA_PLATFORM=TERMINAL with any renderer except SOFTWARE, HEADLESS, STUB | A terminal has no graphical native window a GPU API could bind to; it presents finished CPU frames. |
CNA_ENABLE_SDL=OFF with platform SDL3, audio SDL3, or renderer SDL_RENDERER/SDL_GPU/FNA3D (also inside CNA_GRAPHICS_RENDERERS) | “This configuration genuinely requires SDL”; the message lists which selections do. Because the platform and audio defaults are both SDL3, an SDL-free build must set both explicitly. |
CNA_PLATFORM=X11 or WAYLAND when the development packages are missing | The message names the packages to install and explicitly refuses to fall back to SDL3. |
CNA_PLATFORM=WIN32 off Windows, TERMINAL on Windows, SDL12, EMSCRIPTEN | Reserved identifiers, “NOT implemented”. (Emscripten as a target OS is real and served by SDL3.) |
CNA_AUDIO_PLATFORM=ALSA on a non-Linux target; OPENAL; WASAPI | ALSA is Linux-only; the other two are reserved names. |
| Any unknown value, or a wrong case | “Not a known platform” / “not a known audio platform”, listing the available and reserved sets. |
A renderer name outside the 18 public identities is refused by the same kind of configure error; see Renderers for the list, and Platform Support for which renderers each target OS offers.
Useful configurations
Default desktop host and audio, explicit renderer
cmake -S ../cna -B build-desktop \
-DCNA_PLATFORM=SDL3 \
-DCNA_GRAPHICS_RENDERER=OPENGLES3 \
-DCNA_AUDIO_PLATFORM=SDL3
No display and no high-level sound engine
cmake -S ../cna -B build-headless \
-DCNA_PLATFORM=HEADLESS \
-DCNA_GRAPHICS_RENDERER=HEADLESS \
-DCNA_AUDIO_PLATFORM=NULL
This is useful for game-logic CI and servers. A headless platform does not secretly force null audio: choose SDL3 (or ALSA) audio if the process should still play sound.
POSIX terminal presentation
cmake -S ../cna -B build-terminal \
-DCNA_PLATFORM=TERMINAL \
-DCNA_GRAPHICS_RENDERER=SOFTWARE \
-DCNA_AUDIO_PLATFORM=NULL
TERMINAL is POSIX-only and accepts exactly three CPU/no-output renderers: SOFTWARE, HEADLESS and STUB. It is not an implemented Windows-console mode. See Tutorial 139.
No SDL at all: native X11
cmake -S ../cna -B build-x11 \
-DCNA_ENABLE_SDL=OFF \
-DCNA_PLATFORM=X11 \
-DCNA_AUDIO_PLATFORM=NULL \
-DCNA_GRAPHICS_RENDERER=HEADLESS
This is the configuration the x11-sdl-free CI job builds and tests under Xvfb, and CI then proves that the test executables link no SDL. Swap in -DCNA_AUDIO_PLATFORM=ALSA and a real renderer such as OPENGL33 for sound and pixels (CI’s x11-sdl-free-gpu job also compiles VULKAN, SOFTWARE and HEADLESS in for run-time selection). The X11 backend needs libx11-dev, libxext-dev and X11/XKBlib.h; the rest of the X libraries are optional and each gates one capability. Tutorial 135 walks through it; the audio half is Tutorial 137.
Native Wayland (no CI)
cmake -S ../cna -B build-wayland \
-DCNA_ENABLE_SDL=OFF \
-DCNA_PLATFORM=WAYLAND \
-DCNA_AUDIO_PLATFORM=NULL \
-DCNA_GRAPHICS_RENDERER=HEADLESS
Needs wayland-client 1.18 or newer, xkbcommon 0.5 or newer, wayland-protocols with stable/xdg-shell, and wayland-scanner. No GitHub workflow builds CNA_PLATFORM=WAYLAND; its tests exist and are run locally. See Tutorial 136 and Native Platforms.
SDL3 window, native audio
cmake -S ../cna -B build-alsa \
-DCNA_PLATFORM=SDL3 \
-DCNA_AUDIO_PLATFORM=ALSA
Legal: the window stays SDL3 while sound goes through ALSA and CNA’s own mixer. Configure needs the ALSA headers (libasound2-dev). This exact pairing is not exercised by CI.
Where there is no SDL-free audio
On Windows and macOS the only audio choices are SDL3 and NULL, and CNA_ENABLE_SDL=OFF refuses the first. An SDL-free native Windows build (CNA_PLATFORM=WIN32) therefore has silent NULL audio; OPENAL and WASAPI are reserved names, not implementations.
Reserved names are not support claims
SDL12 and EMSCRIPTEN are reserved platform identifiers (and WIN32 is reserved off Windows, TERMINAL on Windows); OPENAL and WASAPI are reserved audio identifiers. This snapshot rejects all of them at configure time. Emscripten as a target OS/toolchain is real, but it is not a CNA_PLATFORM=EMSCRIPTEN implementation. Notice what changed since alpha.1: WIN32 and ALSA used to be reserved and are now implemented.
Verify the configured axes
cmake -LA -N build-headless | grep -E 'CNA_(PLATFORM|GRAPHICS_RENDERER|AUDIO_PLATFORM|ENABLE_SDL)'
ctest --test-dir build-headless -N
The generated test inventory changes with all of these selections and with feature options. Report the values beside test results; a number without its configuration is not reproducible. The configure log also prints CNA: Using <NAME> platform implementation and CNA: Using <NAME> audio platform implementation.
Next steps
- Platform support reference
- Native Platforms (X11, Wayland, Win32)
- Audio reference
- Complete build options
- Tutorial 126: Multi-renderer builds
- Tutorial 138: Building without SDL
- Tutorial 137: Native Linux audio with ALSA
Deep dives on this topic
Long-form pages that explain the exact semantics, invariants and evidence behind this subject.
- The cross-platform contract: axes, composition and evidence per route — How target OS, platform implementation, renderer set, audio implementation and the XNA surface compose in CNA, what IPlatform owns, and why each platform claim is an evidence vector.