Tutorial 20: Building and Running Your Game

Build System  ·  CMake  ·  Emscripten  ·  Android

CNA uses CMake as its build system. This tutorial covers release builds for Linux and Windows, the ctest sanity check, WebAssembly via Emscripten, Android APK packaging, and a CMakeLists.txt install target that bundles your game with its assets.

CMake release build (Linux)

## Configure a release build with the EasyGL backend
cmake -S . -B build-release \
      -DCMAKE_BUILD_TYPE=Release \
      -DCNA_GRAPHICS_BACKEND=EASYGL

## Build only your game target (faster than building everything)
cmake --build build-release --target MyGame --parallel

## Run
./build-release/MyGame

Release mode enables -O3 (GCC/Clang) or /O2 (MSVC) and strips debug symbols. Expect 3–10x faster rendering on CPU-bound scenes compared to Debug.

ctest sanity check

Before shipping, run the CNA test suite to confirm your dependencies and build configuration are sane:

cmake --build build-release --target CnaTests
ctest --test-dir build-release --output-on-failure --parallel 4

All 4,373 unit tests should pass. If any fail, your compiler or CNA version may be incompatible.

Windows executable

:: Configure (PowerShell or cmd.exe)
cmake -S . -B build-win-release ^
      -DCMAKE_BUILD_TYPE=Release ^
      -DCNA_GRAPHICS_BACKEND=EASYGL

:: Build
cmake --build build-win-release --target MyGame --config Release

:: Run
build-win-release\Release\MyGame.exe

On Windows with MSVC, SDL3.dll is placed alongside the executable automatically by the build system. No additional DLL redistribution steps are required for self-contained distribution.

Linux executable packaging

For distributing to end users on Linux, bundle your executable with its assets:

# In CMakeLists.txt — install target
install(TARGETS MyGame DESTINATION .)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/assets DESTINATION .)
install(FILES ${CMAKE_SOURCE_DIR}/README.txt DESTINATION .)

# Build the install tree
cmake --install build-release --prefix dist/linux-x64

# dist/linux-x64/ now contains:
#   MyGame
#   assets/
#   README.txt

For AppImage packaging, run linuxdeploy on the install prefix. For Flatpak, add a CNA module to your manifest and point to the install prefix.

Emscripten WebAssembly build

CNA supports Emscripten 3.1+ for web deployment. You need the Emscripten SDK installed and activated (source emsdk_env.sh).

## Configure with the Emscripten toolchain
emcmake cmake -S . -B build-web \
      -DCMAKE_BUILD_TYPE=Release \
      -DCNA_GRAPHICS_BACKEND=EASYGL \
      -DCNA_PLATFORM=WEB

## Build
cmake --build build-web --target MyGame

## Output files:
##   build-web/MyGame.js
##   build-web/MyGame.wasm
##   build-web/MyGame.html   (auto-generated shell page)
##   build-web/MyGame.data   (packaged assets)

Assets are packaged into the .data file by Emscripten's --preload-file mechanism. In your CMakeLists.txt:

if(EMSCRIPTEN)
    set_target_properties(MyGame PROPERTIES
        SUFFIX ".html"
        LINK_FLAGS
            "-s USE_SDL=3 \
             -s USE_SDL_IMAGE=3 \
             -s USE_SDL_MIXER=3 \
             -s ASYNCIFY \
             -s ALLOW_MEMORY_GROWTH=1 \
             --preload-file ${CMAKE_SOURCE_DIR}/assets@/assets"
    )
endif()

Serve the output directory with any HTTP server — browsers block file:// access to .wasm files:

cd build-web
python3 -m http.server 8080
# Open http://localhost:8080/MyGame.html

Android APK overview

Android support in CNA uses SDL3's Android build infrastructure. The high-level steps are:

  1. Install Android NDK r25+ and Android SDK with API level 24+.
  2. Copy the SDL3 Android project template from third_party/SDL/android-project/.
  3. Configure the Gradle build to reference your CNA library as a native dependency.
  4. Place assets in src/main/assets/.
  5. Run ./gradlew assembleRelease to produce an APK.
## CMake cross-compile for Android ARM64
cmake -S . -B build-android \
      -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
      -DANDROID_ABI=arm64-v8a \
      -DANDROID_PLATFORM=android-24 \
      -DCNA_GRAPHICS_BACKEND=EASYGL \
      -DCNA_PLATFORM=ANDROID \
      -DCMAKE_BUILD_TYPE=Release

cmake --build build-android --target MyGame

See the Platforms documentation for a full step-by-step Android setup guide.

Packaging assets with CPack

CPack can produce a ZIP, DEB, or NSIS installer automatically:

## CMakeLists.txt additions for CPack
set(CPACK_PACKAGE_NAME        "MyGame")
set(CPACK_PACKAGE_VERSION     "1.0.0")
set(CPACK_PACKAGE_VENDOR      "My Studio")
set(CPACK_GENERATOR           "ZIP;DEB")   # or NSIS on Windows

include(CPack)
install(TARGETS MyGame DESTINATION bin)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/assets DESTINATION share/MyGame)
## Generate the package
cmake --build build-release --target package

## Output:
##   build-release/MyGame-1.0.0-Linux.zip
##   build-release/MyGame-1.0.0-Linux.deb

Full CMakeLists.txt example

cmake_minimum_required(VERSION 3.20)
project(MyGame VERSION 1.0.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Pull in CNA (assumes sibling directory layout)
add_subdirectory(../cna cna-build)

add_executable(MyGame
    src/main.cpp
    src/MyGame.cpp
    src/states/MainMenuState.cpp
    src/states/GameplayState.cpp
)

target_link_libraries(MyGame PRIVATE CNA)

# Copy assets to build dir for development convenience
add_custom_command(TARGET MyGame POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        ${CMAKE_SOURCE_DIR}/assets $<TARGET_FILE_DIR:MyGame>/assets
)

# Install rules
install(TARGETS MyGame DESTINATION .)
install(DIRECTORY assets DESTINATION .)

# CPack
set(CPACK_PACKAGE_NAME    "MyGame")
set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
set(CPACK_GENERATOR       "ZIP")
include(CPack)