Tutorial 02: Setting Up Your Dev Environment

CNA Tutorial Series  ·  Beginner

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 startTutorial 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

ComponentRequirement
CompilerGCC 12+ or Clang 15+ (C++23 required); MSVC 2022 v17.8+ on Windows
Build systemCMake 3.20+
GPU driverOpenGL ES 3.0 or OpenGL 3.0+ for the OPENGLES3 renderer
RAM4 GB minimum for compilation (8 GB recommended)
Disk~500 MB for source and build artifacts
OSLinux (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)

  1. Install Visual Studio 2022 with the "Desktop development with C++" workload.
  2. Install CMake 3.20+ and add it to PATH.
  3. 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:

SiblingNeeded for
sharp-runtimeEvery build, without exception
easy-glThe five GL-profile renderers: OPENGLES2, OPENGLES3, OPENGL33, WEBGL1, WEBGL2
meta-glRequired 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

OptionValuesDefault
CNA_GRAPHICS_RENDERERAny one of the 50 renderer identities, e.g. SDL_RENDERER, OPENGLES3, VULKAN, BGFX, SDL_GPUOPENGLES3 on Linux, WEBGL2 under Emscripten, SDL_RENDERER otherwise
CMAKE_BUILD_TYPEDebug, Release, RelWithDebInfoDebug
CNA_BUILD_TESTSON, OFFON
CNA_CNAEXTON, OFFOFF — gates the CNAEXT engine layer (AsciiPostProcessEffect, CRTEffect, DepthEffect, PbrMaterial, CNA::Graphics)
CNA_DEVICESON, OFFOFF — gates the CNAEXT device layer
CNA_STRICT_XNA_APION, OFFOFF — purity mode: touching any CNA extension becomes a compile error
CNA_ENABLE_NETON, OFFNetworking 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

  1. Install the C/C++ extension and the CMake Tools extension.
  2. Open the cna/ folder in VS Code.
  3. CMake Tools will detect CMakeLists.txt automatically. Select your kit (GCC 12 or Clang 15).
  4. 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.
  5. Press F7 to 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

  1. Open the cna/ directory as a CLion project.
  2. CLion auto-detects CMakeLists.txt. Go to Settings → Build, Execution, Deployment → CMake.
  3. Add a CMake profile and set CMake options: -DCNA_GRAPHICS_RENDERER=OPENGLES3.
  4. Choose the toolchain (GCC or Clang). Make sure it points to a C++23-capable version.
  5. 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.