Tutorial 100: Shipping Your CNA Game

CNA — C++ XNA 4.0 reimplementation

Release CMake build

# Release build with maximum optimization
cmake -S . -B build-release \
  -DCMAKE_BUILD_TYPE=Release \
  -DCNA_GRAPHICS_BACKEND=EASYGL \
  -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON   # LTO

cmake --build build-release -j$(nproc)

Stripping debug symbols

# Linux: strip symbols to reduce binary size
strip --strip-unneeded build-release/MyGame

# Keep debug symbols separately for crash reports:
objcopy --only-keep-debug build-release/MyGame build-release/MyGame.debug
strip --strip-unneeded build-release/MyGame
objcopy --add-gnu-debuglink=MyGame.debug build-release/MyGame

Asset bundling

Place all game assets in an assets/ directory alongside the executable. For web builds, preload via Emscripten. For compressed bundles, use a simple ZIP archive (extract at first run) or a custom pack format.

# Copy assets to build output directory
add_custom_command(TARGET MyGame POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
            ${CMAKE_SOURCE_DIR}/assets
            $<TARGET_FILE_DIR:MyGame>/assets
    COMMENT "Copying assets"
)

Windows installer (NSIS/WiX)

# CPack NSIS installer (Windows)
set(CPACK_GENERATOR "NSIS")
set(CPACK_PACKAGE_NAME "MyGame")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_PACKAGE_VENDOR "My Studio")
set(CPACK_NSIS_DISPLAY_NAME "My Game")
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/icon.ico")

install(TARGETS MyGame DESTINATION .)
install(DIRECTORY assets DESTINATION .)
include(CPack)

Linux AppImage/Flatpak

# Create AppImage with linuxdeploy
wget https://github.com/linuxdeploy/linuxdeploy/releases/latest/download/linuxdeploy-x86_64.AppImage
chmod +x linuxdeploy-x86_64.AppImage
./linuxdeploy-x86_64.AppImage \
  --appdir AppDir \
  --executable build-release/MyGame \
  --desktop-file mygame.desktop \
  --icon-file mygame.png \
  --output appimage
# mygame.desktop
[Desktop Entry]
Type=Application
Name=My Game
Exec=MyGame
Icon=mygame
Categories=Game;

Web deployment (GitHub Pages / itch.io)

# Build for web
cmake -S . -B build-wasm \
  -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake \
  -DCNA_GRAPHICS_BACKEND=EASYGL -DCMAKE_BUILD_TYPE=Release
cmake --build build-wasm -j$(nproc)

# Deploy to GitHub Pages (gh-pages branch):
git checkout gh-pages
cp build-wasm/MyGame.{html,js,wasm,data} docs/
git add docs/
git commit -m "Deploy web build"
git push

# Or upload to itch.io using butler:
butler push docs/ yourstudio/mygame:html5

Android Play Store

Build and sign a release APK:

# 1. Build release APK
cd android/
./gradlew assembleRelease

# 2. Sign with release keystore
jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 \
  -keystore my-release-key.keystore \
  app/build/outputs/apk/release/app-release-unsigned.apk \
  my-alias

# 3. Align with zipalign
zipalign -v 4 app-release-unsigned.apk my-game-release.apk

# 4. Upload to Play Console via fastlane or the web UI

License compliance (Ms-PL + SDL3 + dependencies)

CNA is licensed under the Microsoft Public License (Ms-PL). Your shipped game must include:

  • LICENSE file from the CNA repository (Ms-PL)
  • SDL3 license: zlib license (permissive, requires attribution in documentation)
  • SDL3_image: zlib license
  • SDL3_mixer: zlib license
  • If using Vulkan: the Vulkan SDK components are Apache 2.0
  • If using Box2D: MIT license
  • If using Bullet: zlib license

All permissive — no copyleft restrictions. Include a LICENSES.txt in your distribution:

CNA -- Microsoft Public License (Ms-PL)
SDL3 -- zlib License, Copyright (C) 1997-2024 Sam Lantinga
SDL3_image -- zlib License
SDL3_mixer -- zlib License
[add any other dependencies]

Final checklist

CPack CMakeLists.txt for multi-platform packaging:

cmake_minimum_required(VERSION 3.20)
project(MyGame CXX)
set(CMAKE_CXX_STANDARD 23)

# ... your normal target setup ...

# ---- CPack configuration ----
set(CPACK_PACKAGE_NAME       "MyGame")
set(CPACK_PACKAGE_VERSION    "1.0.0")
set(CPACK_PACKAGE_VENDOR     "My Studio")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "An awesome CNA game")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSES.txt")

if(WIN32)
    set(CPACK_GENERATOR "NSIS;ZIP")
    set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
    set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
elseif(APPLE)
    set(CPACK_GENERATOR "DragNDrop")
elseif(UNIX)
    set(CPACK_GENERATOR "TGZ;DEB")
    set(CPACK_DEBIAN_PACKAGE_MAINTAINER "you@example.com")
    set(CPACK_DEBIAN_PACKAGE_DEPENDS "libgl1")
endif()

install(TARGETS MyGame DESTINATION bin)
install(DIRECTORY assets DESTINATION bin)
install(FILES LICENSES.txt DESTINATION .)

include(CPack)

# Build package: cmake --build build-release --target package

Shipping checklist:

  • Release build compiled with -O2/-O3 and LTO enabled
  • Debug symbols stripped from release binary (separate .debug file kept)
  • All assets copied to distribution directory
  • 4,373 CNA unit tests pass on target platform
  • Game runs without crash on fresh OS install (no missing DLLs / .so files)
  • Audio tested (SoundEffect, background music)
  • Input tested (keyboard, controller if supported)
  • Window resizing and fullscreen toggle tested
  • LICENSES.txt included in distribution
  • Web build tested in Chrome and Firefox
  • Android APK signed with release keystore