Tutorial 02: Setting Up Your Dev Environment
What you’ll learn
- Installing the toolchain and system dependencies CNA needs.
- Cloning CNA together with its sibling repositories and configuring the build.
- Running the test suite to confirm the build is healthy.
- Getting your IDE to resolve CNA headers.
Before you start — Tutorial 01: Introduction to CNA for context, though nothing here depends on it. You need a working C++ compiler and CMake before you begin.
System Requirements
| Component | Requirement |
|---|---|
| Compiler | GCC 12+ or Clang 15+ (C++23 required); MSVC 2022 v17.8+ on Windows |
| Build system | CMake 3.20+ |
| GPU driver | OpenGL ES 3.0 or OpenGL 3.0+ for the OPENGLES3 renderer |
| RAM | 4 GB minimum for compilation (8 GB recommended) |
| Disk | ~500 MB for source and build artifacts |
| OS | Linux (Ubuntu 22.04+, Fedora 36+, Arch), Windows 10+, macOS 12+ (experimental) |
SDL3, SDL3_image, and SDL3_mixer are compiled from vendored submodules. You do not need to install them from your OS package manager.
FFmpeg is a hard requirement on Linux and macOS. There is no CMake option to disable it: configure fails outright without the libavcodec, libavformat, libavutil and libswresample development packages. They are included in the package lists below.
Installing Dependencies
Ubuntu / Debian
sudo apt update
sudo apt install -y \
build-essential \
gcc-12 g++-12 \
cmake \
git \
ninja-build \
libgl1-mesa-dev \
libgles2-mesa-dev \
libasound2-dev \
libpulse-dev \
libavcodec-dev \
libavformat-dev \
libavutil-dev \
libswresample-dev \
pkg-config
If GCC 12 is not the default on your system, set it explicitly:
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 100
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 100
Verify the C++23 support:
g++ --version # should print gcc 12 or newer
g++ -std=c++23 -x c++ - <<< "int main(){}" && echo "C++23 OK"
Fedora / RHEL
sudo dnf install -y \
gcc gcc-c++ \
cmake \
git \
ninja-build \
mesa-libGL-devel \
mesa-libGLES-devel \
alsa-lib-devel \
pulseaudio-libs-devel \
ffmpeg-free-devel \
pkg-config
On RHEL and derivatives the FFmpeg development headers come from RPM Fusion as ffmpeg-devel instead. Whichever package name your distribution uses, you need headers and link libraries for libavcodec, libavformat, libavutil and libswresample.
Arch Linux
sudo pacman -Syu base-devel cmake git ninja mesa ffmpeg
Windows (MSVC)
- Install Visual Studio 2022 with the "Desktop development with C++" workload.
- Install CMake 3.20+ and add it to
PATH. - Install Git for Windows.
Open a "Developer Command Prompt for VS 2022" for all subsequent commands.
Cloning CNA and its sibling repositories
CNA's companion libraries are separate checkouts placed next to cna/, not submodules. A default Linux build needs three of them, because the Linux default renderer is OPENGLES3, which is implemented by EasyGL:
| Sibling | Needed for |
|---|---|
sharp-runtime | Every build, without exception |
easy-gl | The five GL-profile renderers: OPENGLES2, OPENGLES3, OPENGL33, WEBGL1, WEBGL2 |
meta-gl | Required by easy-gl |
free-direct (with free-api) | Only the FREEDIRECT renderer |
mkdir my-cna-workspace
cd my-cna-workspace
# Clone sharp-runtime first (required by every build)
git clone https://github.com/openeggbert/sharp-runtime.git
# EasyGL and its own dependency — needed for the default Linux renderer
git clone https://github.com/openeggbert/easy-gl.git
git clone https://github.com/openeggbert/meta-gl.git
# Clone CNA
git clone https://github.com/openeggbert/cna.git
# Initialize CNA's vendored submodules (SDL3, SDL3_image, SDL3_mixer, googletest).
# Non-recursive is correct here, and much faster.
cd cna
git submodule update --init
After this, your workspace should look like:
my-cna-workspace/
├── sharp-runtime/ ← C# primitive types for C++
├── easy-gl/ ← the GL-profile renderer implementation
├── meta-gl/ ← required by easy-gl
└── cna/ ← the main CNA repository
├── include/
├── src/
├── tests/
├── vendor/
│ └── googletest/
└── third_party/
├── SDL/
├── SDL_image/
└── SDL_mixer/
Important: the sibling directories must sit next to cna/, not inside it. CMake looks for them at ../sharp-runtime, ../easy-gl and so on, relative to the CNA root.
Building CNA
OPENGLES3 (recommended, full 2D and 3D)
From inside the cna/ directory. This is also what you get on Linux if you pass no renderer flag at all:
cmake -S . -B build \
-DCNA_GRAPHICS_RENDERER=OPENGLES3 \
-DCMAKE_BUILD_TYPE=Debug
cmake --build build --target CnaTests -j$(nproc)
SDL_RENDERER (2D only, fewest dependencies)
This one needs no easy-gl/meta-gl checkout, which makes it the quickest way to get a first build going — at the cost of 3D, which throws:
cmake -S . -B build-sdl \
-DCNA_GRAPHICS_RENDERER=SDL_RENDERER \
-DCMAKE_BUILD_TYPE=Debug
cmake --build build-sdl --target CnaTests -j$(nproc)
--target CNA does not work. CNA is an INTERFACE umbrella library with no sources of its own, so it is not a buildable target. Build CnaTests, build a demo target, or just run cmake --build build with no --target at all. You will still find the old command in some upstream documentation.
Release build
cmake -S . -B build-release \
-DCNA_GRAPHICS_RENDERER=OPENGLES3 \
-DCMAKE_BUILD_TYPE=Release
cmake --build build-release -j$(nproc)
Windows (MSVC Developer Prompt)
cmake -S . -B build -DCNA_GRAPHICS_RENDERER=OPENGLES3
cmake --build build --config Debug --target CnaTests
CMake options reference
| Option | Values | Default |
|---|---|---|
CNA_GRAPHICS_RENDERER | Any one of the 50 renderer identities, e.g. SDL_RENDERER, OPENGLES3, VULKAN, BGFX, SDL_GPU | OPENGLES3 on Linux, WEBGL2 under Emscripten, SDL_RENDERER otherwise |
CMAKE_BUILD_TYPE | Debug, Release, RelWithDebInfo | Debug |
CNA_BUILD_TESTS | ON, OFF | ON |
CNA_CNAEXT | ON, OFF | OFF — gates the CNAEXT engine layer (AsciiPostProcessEffect, CRTEffect, DepthEffect, PbrMaterial, CNA::Graphics) |
CNA_DEVICES | ON, OFF | OFF — gates the CNAEXT device layer |
CNA_STRICT_XNA_API | ON, OFF | OFF — purity mode: touching any CNA extension becomes a compile error |
CNA_ENABLE_NET | ON, OFF | Networking support |
Instead of naming the renderer with CNA_GRAPHICS_RENDERER you may turn on exactly one -DCNA_RENDERER_<NAME>=ON switch. The two forms are equivalent and must not be mixed. CNA also ships CMake presets — web, tests, devices-asan, devices-tsan and devices-ubsan — usable with cmake --preset tests.
The C++ framework has no general install/export package. C++ consumers bring it into their own build with add_subdirectory; see Tutorial 03. The experimental C layer declares a separate CNACApi package, but alpha.1 cannot compile its final implementation because the C renderer identity table omits NanoVG.
Running the Test Suite
At the alpha.1 tag, CNA ships 568 C++ test source files containing 8,263 statically discoverable GoogleTest-family definitions, covering math types, geometry, curves, packed vectors, game loop semantics, renderer cases, and more. The tests compiled and registered with CTest depend on the selected renderer, platform, audio implementation, options, and host. After building the CnaTests target, run the tests present in that build with CTest:
# Run all tests
ctest --test-dir build --output-on-failure
# Run with verbose output
ctest --test-dir build -V
# Run a specific test by name pattern
ctest --test-dir build -R Vector2
# Run and show only failures
ctest --test-dir build --output-on-failure -Q
Expected output:
Test project /home/you/my-cna-workspace/cna/build
Start 1: MathTests
1/8 Test #1: MathTests .................... Passed 0.12 sec
Start 2: ColorTests
2/8 Test #2: ColorTests ................... Passed 0.04 sec
...
100% tests passed, 0 tests failed
The exact test count depends on which renderer you configured, because renderer tests are registered only for the family you compiled. If something fails on a clean build, please open an issue.
CTest labels use the renderer names, so ctest -L DIRECTX9 and ctest -R DIRECTX11 work while the older -L D3D9 / -R D3D11 forms match nothing at all.
You can also run the test binary directly:
./build/CnaTests --gtest_filter="Vector*"
IDE Setup
VS Code
- Install the C/C++ extension and the CMake Tools extension.
- Open the
cna/folder in VS Code. - CMake Tools will detect
CMakeLists.txtautomatically. Select your kit (GCC 12 or Clang 15). - In the status bar, choose the renderer: click "No Configure Preset" and add a configure preset, or use the CMake Tools settings to pass
-DCNA_GRAPHICS_RENDERER=OPENGLES3. - Press
F7to build, or click the build button in the status bar.
For IntelliSense to find CNA headers, CMake Tools generates a compile_commands.json automatically. If IntelliSense is confused, run "CMake: Configure" from the command palette.
CLion
- Open the
cna/directory as a CLion project. - CLion auto-detects CMakeLists.txt. Go to Settings → Build, Execution, Deployment → CMake.
- Add a CMake profile and set CMake options:
-DCNA_GRAPHICS_RENDERER=OPENGLES3. - Choose the toolchain (GCC or Clang). Make sure it points to a C++23-capable version.
- Build with
Ctrl+F9.
CLion's indexer will pick up all CNA headers from the include/ directory automatically once the CMake project is configured.
Neovim / Emacs (compile_commands.json)
CNA's CMake build generates build/compile_commands.json. Point your LSP (clangd) at it:
# Generate compile_commands.json
cmake -S . -B build -DCNA_GRAPHICS_RENDERER=OPENGLES3 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
# Symlink to project root for clangd
ln -s build/compile_commands.json compile_commands.json
clangd will then provide completion and diagnostics across all CNA headers.
The first build takes several minutes because CMake builds SDL3 from source. Subsequent incremental builds are much faster. Use -j$(nproc) (Linux/macOS) or --parallel (Windows) to parallelize.
With your environment set up and the tests passing, you are ready to write your first CNA game. Continue to Tutorial 03: Your First CNA Window.