Tutorial 100: Shipping Your CNA Game
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:
LICENSEfile 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