Minimal C/SDL2 renderer with Python (ctypes) driving the game logic. Supports macOS, Windows, and Linux. The C side draws a 2D flat-top hex grid; Python sends batches of hex instances each frame.
- C toolchain (Clang/MSVC/GCC)
- CMake ≥ 3.18 and Ninja (or Make)
- SDL2 (and optionally:
sdl2_image,sdl2_mixer,sdl2_ttf,sdl2_gfx) - Python 3.10+ (no third-party libs required;
ctypesonly)
# 0) Xcode Command Line Tools (CLT)
xcode-select --install
# 1) (Optional) Newer LLVM/Clang than Apple Clang
brew update
brew install llvm
echo 'export PATH="$(brew --prefix llvm)/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc
# 2) Build essentials
brew install cmake ninja pkg-config
# 3) SDL2 + common add-ons
brew install sdl2 sdl2_image sdl2_mixer sdl2_ttf sdl2_gfx
# 4) Python (virtualenv recommended)
python3 -m venv .venv && source .venv/bin/activate
pip install --upgrade pip
pip install pysdl2Sanity checks
cc --version
sdl2-config --version
pkg-config --modversion sdl2- Install MSYS2, open MSYS2 UCRT64 shell:
pacman -Syu # may need to close/reopen once
pacman -S --needed mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-clang \
mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-ninja \
mingw-w64-ucrt-x86_64-pkg-config git
pacman -S --needed mingw-w64-ucrt-x86_64-SDL2 \
mingw-w64-ucrt-x86_64-SDL2_image \
mingw-w64-ucrt-x86_64-SDL2_mixer \
mingw-w64-ucrt-x86_64-SDL2_ttf \
mingw-w64-ucrt-x86_64-SDL2_gfx
pacman -S --needed mingw-w64-ucrt-x86_64-python-pip
python -m venv .venv && source .venv/Scripts/activate
pip install --upgrade pip
pip install pysdl2winget install --id Microsoft.VisualStudio.2022.BuildTools --silent
winget install Git.Git Kitware.CMake Ninja-build.Ninja LLVM.LLVM
git clone https://github.com/microsoft/vcpkg $env:USERPROFILE\vcpkg
& $env:USERPROFILE\vcpkg\bootstrap-vcpkg.bat
$env:VCPKG_DEFAULT_TRIPLET="x64-windows"
$VCP=$env:USERPROFILE+"\vcpkg"
& $VCP\vcpkg.exe install sdl2 sdl2-image sdl2-mixer sdl2-ttf sdl2-gfx
py -m venv .venv
.\.venv\Scripts\activate
pip install --upgrade pip
pip install pysdl2 pysdl2-dllBuild with:
cmake -B build -S . -G "Ninja" -DCMAKE_TOOLCHAIN_FILE=$VCP\scripts\buildsystems\vcpkg.cmake -A x64
cmake --build build --config Releasesudo apt update
sudo apt install -y build-essential clang pkg-config cmake ninja-build git \
libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev libsdl2-gfx-dev
python3 -m venv .venv && source .venv/bin/activate
pip install --upgrade pip
pip install pysdl2sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y clang cmake ninja-build pkg-config git \
SDL2-devel SDL2_image-devel SDL2_mixer-devel SDL2_ttf-devel SDL2_gfx-devel
python3 -m venv .venv && source .venv/bin/activate
pip install --upgrade pip
pip install pysdl2sudo pacman -Syu
sudo pacman -S --needed base-devel clang cmake ninja pkgconf git \
sdl2 sdl2_image sdl2_mixer sdl2_ttf sdl2_gfx
python -m venv .venv && source .venv/bin/activate
pip install --upgrade pip
pip install pysdl2# from repo root
mkdir -p build && cd build
cmake -G Ninja ..
ninja
# optional C demo
./hex_demo
# Python-controlled renderer
cd ..
python3 python_demo.py
# Hex strategy sandbox (texture-rendered)
python3 python_strategy_demo.pyThe strategy sandbox looks for the asset paths defined near the top of python_strategy_demo.py. If no image is present, the script drops in simple placeholder BMPs so you can replace them with your own artwork later.
- Controls:
WASDpans the camera,=/-(or keypad ±) zoom in/out, left-click selects units, right-click issues move orders.
- After editing any C source or headers, rebuild with
cmake --build build(orninja -C build). This recompiles only the targets that changed—no need to reruncmakeunless you touchCMakeLists.txtor change build options. - To rebuild just the shared library that Python loads:
cmake --build build --target hexlib(orninja -C build libhexlib.dylib). - To rebuild the standalone demo executable:
cmake --build build --target hex_demo. - If you ever delete the
build/directory, recreate it and reconfigure withcmake -S . -B buildbefore building again.
On macOS, you can be explicit about the SDK if needed:
cmake -G Ninja -D CMAKE_OSX_SYSROOT="$(xcrun --show-sdk-path)" ..
If CMake says the compiler can't build a simple test or you see messages like:
xcodebuild: error: SDK ".../MacOSX15.5.sdk" cannot be located.xcrun: error: unable to find utility "clang"
You probably have a stale developer path or a phantom SDKROOT.
Fix:
# remove bad env in your shell
unset SDKROOT
unset DEVELOPER_DIR
# reset/select the real Xcode
sudo xcode-select --reset
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
sudo xcodebuild -license accept
# verify
xcrun --find clang
xcodebuild -showsdks | grep -i macos
ls -1 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKsIf xcrun --find clang still fails, open Xcode once and set Preferences → Locations → Command Line Tools to your installed Xcode 16.x.
If pkg-config --modversion sdl2 says "No package 'sdl2' found":
# confirm where Homebrew installed SDL2's .pc
brew --prefix sdl2
ls -1 "$(brew --prefix sdl2)"/lib/pkgconfig/sdl2.pc
# set PKG_CONFIG_PATH for the session
export PKG_CONFIG_PATH="$(brew --prefix sdl2)/lib/pkgconfig:$(brew --prefix)/lib/pkgconfig:$(brew --prefix)/share/pkgconfig:$PKG_CONFIG_PATH"
# optional: make it permanent
echo 'export PKG_CONFIG_PATH="$(brew --prefix sdl2)/lib/pkgconfig:$(brew --prefix)/lib/pkgconfig:$(brew --prefix)/share/pkgconfig:$PKG_CONFIG_PATH"' >> ~/.zshrc
source ~/.zshrcWe use pkg-config if available and fall back to SDL2's CMake package:
find_package(PkgConfig QUIET)
if(PkgConfig_FOUND)
pkg_check_modules(SDL2 IMPORTED_TARGET sdl2)
endif()
add_library(hexlib SHARED src/hexlib.c)
target_include_directories(hexlib PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_compile_definitions(hexlib PRIVATE HEXLIB_BUILD)
if(TARGET PkgConfig::SDL2)
target_link_libraries(hexlib PRIVATE PkgConfig::SDL2)
else()
find_package(SDL2 CONFIG REQUIRED) # Homebrew: /opt/homebrew/lib/cmake/SDL2
target_link_libraries(hexlib PRIVATE SDL2::SDL2)
endif()
add_executable(hex_demo src/main.c)
target_include_directories(hex_demo PRIVATE ${PROJECT_SOURCE_DIR}/include)
if(TARGET PkgConfig::SDL2)
target_link_libraries(hex_demo PRIVATE hexlib PkgConfig::SDL2)
else()
target_link_libraries(hex_demo PRIVATE hexlib SDL2::SDL2)
endif()If you still see link-time ld: library 'SDL2' not found, you're passing -lSDL2 without the -L path. Using PkgConfig::SDL2 or SDL2::SDL2 fixes that (they carry the proper include, lib, and framework flags).
| Symptom | Cause | Fix |
|---|---|---|
SDK "...MacOSX*.sdk" cannot be located |
Stale SDKROOT/CLT after macOS upgrade |
unset SDKROOT && xcode-select --reset && --switch /Applications/Xcode.app/Contents/Developer |
xcrun: unable to find utility "clang" |
CLT/Xcode not selected | Open Xcode → set Command Line Tools, or run the xcode-select steps above |
pkg-config: No package 'sdl2' found |
PKG_CONFIG_PATH missing Homebrew dirs |
Export PKG_CONFIG_PATH to include $(brew --prefix sdl2)/lib/pkgconfig |
ld: library 'SDL2' not found |
Linking with -lSDL2 but missing -L |
Use PkgConfig::SDL2 or SDL2::SDL2 in CMake |
| Blue screen, only outlines drawn | Using older SDL2 without SDL_RenderGeometry |
Either update SDL2 or keep outline rendering / link sdl2_gfx |
# C demo
./build/hex_demo
# Python
python3 python_demo.pyYou should see a dark background with a hex grid; clicks create a small ring animation and the background pulses over time.
include/hexlib.h # public C API (shared with Python ctypes)
src/hexlib.c # SDL2 renderer + hex math
src/main.c # optional standalone C demo
python_demo.py # Python controller using ctypes
CMakeLists.txt
MIT (see LICENSE).