C++ Cross-Platform Dev Cookbook — one-liners, tools, and patterns for game dev, research, and reverse engineering.
Install once. Use everywhere. Copy-paste friendly.
| # | Topic | What | Deep Dive |
|---|---|---|---|
| 0 | Install | One-command install per platform | tools-install.md |
| 1 | CMake | CLI one-liners: configure, build, test, pro tricks | cmake.md |
| 2 | Project Navigation | Study any repo fast: blame, history, diff, AI | project-navigation.md |
| 3 | Git & lazygit | Rebase, bisect, stash, cherry-pick, lazygit TUI | git-tricks.md |
| 4 | Shell Tricks | <() process substitution, pipes, parallel, aliases |
shell-tricks.md |
| 5 | Build Speed | ccache, Ninja, PCH, unity | build-acceleration.md |
| 6 | Search | ripgrep, fd, fzf, bat | search-navigation.md |
| 7 | Static Analysis | cppcheck, clang-tidy, ast-grep | static-analysis.md |
| 8 | Debug & Profile | GDB/LLDB, threads, reverse debug, crash dumps (all platforms) | debugging-profiling.md |
| 9 | Network Debug | tcpdump, Wireshark, DNS, TLS, why can't it connect | network-debugging.md |
| 10 | Cross-Compile | Zig, Android, iOS | cross-compilation.md |
| 11 | Packages | vcpkg, Conan, FetchContent | cmake-package-managers.md |
| 12 | Task Runner | just — never type cmake again | justfile.md |
| 13 | Benchmarking | hyperfine, Google Benchmark | benchmarking.md |
| 14 | File Tracking | What did that command produce? | ↓ |
| 15 | Mobile Dev | ADB, root, Xcode, devicectl, LLDB | mobile.md |
| 16 | Reverse Engineering | Ghidra, r2, x64dbg, WinDbg | reverse-engineering.md |
| 17 | Binary Tools | UPX, hex, PE, shipping | binary-tools.md |
| 18 | Controls & Input | Steam Golden Rules, gamepad | controls.md |
| 19 | Windows | Dev Mode, WSL, Terminal, PowerToys, MSVC, CRT, PDB | windows-cpp.md |
| 20 | Resources | Books, talks, channels | resources.md |
| 21 | USB-C Gamedev | SDL3 gamepad, DP Alt Mode, PD charging, cables, docks | usb-c-gamedev.md |
Scoop preferred on Windows. Full table with every tool: tools-install.md
# 🪟 Windows (scoop — no admin needed, clean install to ~/scoop/)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
scoop install git cmake ninja ccache ripgrep fd bat fzf just llvm zig lazygit
# 🐧 Linux (Ubuntu/Debian)
sudo apt update && sudo apt install -y \
build-essential cmake ninja-build ccache gdb lldb clang clang-tidy \
ripgrep fd-find bat fzf strace tcpdump
# 🍎 macOS (get Xcode CLT first for clang + lldb + git)
xcode-select --install
brew install cmake ninja ccache ripgrep fd bat fzf just lazygitFull CLI cookbook with pro tricks: cmake.md See also: Modern CMake guide, Professional CMake book
# THE daily command — debug + ninja + ccache + compile_commands
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
cmake --build build
ln -sf build/compile_commands.json . # clangd/clang-tidy/IDE need this at root
# Build one target
cmake --build build --target myapp
# Test
ctest --test-dir build --output-on-failure
# Sanitizers
cmake -B build -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer" -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined"
# Presets (if project has CMakePresets.json)
cmake --list-presets
cmake --preset dev && cmake --build --preset dev && ctest --preset dev
# Study the project — what targets exist?
cmake --build build --target help | sort
# What features/options does it expose?
cmake -B build -LAH | rg -i "feature|enable|option|with"
# Generate dependency graph (needs graphviz)
cmake -B build --graphviz=deps.dot && dot -Tpng deps.dot -o deps.png
# Profile configure speed (CMake 3.28+)
cmake -B build --profiling-output=prof.json --profiling-format=google-trace
# → open prof.json at https://ui.perfetto.dev
# Cross-compile
cmake -B build/linux -DCMAKE_TOOLCHAIN_FILE=zig-toolchain.cmake
cmake -B build/android -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK/build/cmake/android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-24
cmake -B build/ios -GXcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_ARCHITECTURES=arm64Just cloned a big repo? Full guide: project-navigation.md Git official docs: git-log, git-blame, git-bisect
# What is this project?
scc # language mix + line counts
tree -L 2 --dirsfirst -I 'build|.git|node_modules'
bat README.md
# What does it build?
cmake -B build -G Ninja && cmake --build build --target help | sort
# Who works on it?
git shortlog -sn --all | head -10 # top contributors
git log --oneline -20 # recent activity
# Hottest files (most changed = most complex, most bugs)
git log --format=format: --name-only --since="6 months ago" | sort | uniq -c | sort -rn | head -15# Who wrote this and when?
git blame src/engine/renderer.cpp | bat -l gitblame
git log --oneline -10 -- src/engine/renderer.cpp
# When was this function added?
git log -S "initVulkan" --oneline
# What changed in this file recently?
git diff HEAD~10 -- src/engine/renderer.cpp# aider — AI pair programmer in terminal (https://aider.chat)
pip install aider-chat
aider --read-only src/engine/ # study mode: ask questions about code
# > "explain how the rendering pipeline works"
# > "what are the main abstractions and data flow?"
# GitHub Copilot Chat in terminal (https://cli.github.com)
gh copilot suggest "find all functions that allocate without RAII"
gh copilot explain "git rebase -i HEAD~5"git bisect start
git bisect bad HEAD # current is broken
git bisect good v1.0 # v1.0 was good
# Test each checkout → git bisect good/bad → repeat until found
git bisect reset
# Automated (if you have a test):
git bisect start HEAD v1.0
git bisect run cmake --build build && ctest --test-dir buildFull reference with lazygit keybindings: git-tricks.md Tool: lazygit — TUI git client, makes rebase/bisect/cherry-pick visual
# Install: scoop install lazygit / brew install lazygit / sudo apt install lazygit
lazygit # launch TUI — everything is visual
# Interactive rebase (lazygit: go to Commits [3], press 'e' to edit, 's' to squash)
git rebase -i HEAD~5 # CLI equivalent
# Cherry-pick
git cherry-pick abc1234 # one commit
git cherry-pick abc1234..def5678 # range
# Stash tricks
git stash push -m "WIP: feature X" # named stash
git stash push -- src/a.cpp src/b.cpp # specific files only
git stash push -u -m "with untracked" # include untracked
git stash list # see all stashes
git stash apply stash@{2} # apply without dropping
# Reflog — recover anything
git reflog # every HEAD movement ever
git checkout -b recovered-branch abc1234 # recover deleted branch
# Worktrees — work on multiple branches simultaneously
git worktree add ../project-hotfix hotfix-branch
cd ../project-hotfix # separate dir, same repo
# Pretty log
git log --oneline --graph --decorate --all -30💡 Pro tip: lazygit makes interactive rebase 10× faster. Select commit → press
eto edit,sto squash,dto drop. Resolve conflicts inline. No CLI editor needed.
Full reference with process substitution, pipes, aliases: shell-tricks.md
Did you know?
<()runs a command and gives you a temp file descriptor. No temp files needed.
# Compare two command outputs
diff <(cmake --build build --target help | sort) <(cmake --build build-rel --target help | sort)
# Compare compile_commands between builds
diff <(jq '.[].file' build/compile_commands.json | sort) <(jq '.[].file' build-rel/compile_commands.json | sort)
# Compare git log of two branches
diff <(git log main --oneline -20) <(git log feature --oneline -20)
# Feed multiple sources to one command
cat <(rg "#include" --type cpp --no-filename) <(rg "#include" --type c --no-filename) | sort -u
# Pipe to multiple commands simultaneously
cmake --build build 2>&1 | tee >(grep -i error > errors.log) >(grep -i warning > warnings.log)# xargs with parallel execution
fd -e cpp | xargs -P 8 -I {} clang-format -i {}
# Pipe to clipboard
rg "pattern" --type cpp | xclip -selection clipboard # Linux
rg "pattern" --type cpp | pbcopy # macOS
rg "pattern" --type cpp | clip # Windows
# GNU parallel — process files 8 at a time
fd -e cpp -e hpp | parallel -j8 clang-format -i {}
# Brace expansion — create project structure fast
mkdir -p project/{src/{core,render,audio},include,test,build}
cp main.cpp{,.bak} # same as: cp main.cpp main.cpp.bak# Install fzf key bindings: ~/.fzf/install
# Now you get:
# Ctrl+R = fuzzy history search with preview
# Ctrl+T = fuzzy file search inline
# Alt+C = fuzzy cd
# Fuzzy open file with preview
fd -e cpp | fzf --preview 'bat --style=numbers {}' | xargs vim
# Fuzzy git branch checkout
git branch | fzf | xargs git checkoutFull reference: build-acceleration.md Compiler cache comparison: ccache vs sccache
# ccache — 5-10× faster rebuilds
ccache -s # stats
ccache -C # clear
# Enable in cmake:
cmake -B build -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
# Unity builds (CI only!)
cmake -B build -DCMAKE_UNITY_BUILD=ON| Technique | Cold build | Hot rebuild |
|---|---|---|
| + Ninja | ~80% | ~70% |
| + ccache | ~80% | ~15% |
| + PCH | ~60% | ~50% |
| + Unity | ~25% | n/a |
Full reference: search-navigation.md Tools: ripgrep, fd, fzf, bat
# ripgrep — search code
rg "pattern" --type cpp -n -C 3 # with context
rg "TODO|FIXME|HACK" --type cpp # todos
rg "new\s+\w+" --type cpp # raw owning pointers (smart ptr candidates)
rg "^#include" --type cpp --no-filename | sort -u # all unique includes
# fd — find files
fd -e cpp -e hpp # all C++ files
fd --changed-within 1day # modified today
# fzf — fuzzy find
fd -e cpp | fzf --preview 'bat {}' # fuzzy open with preview
git branch | fzf | xargs git checkout # fuzzy branch switch
# bat — cat with syntax
bat src/main.cpp --diff # show git changes in gutterFull reference: static-analysis.md Tools: cppcheck, clang-tidy, ast-grep
# cppcheck — find bugs without compiling
cppcheck --enable=all --suppress=missingIncludeSystem src/
# clang-tidy (needs compile_commands.json from cmake configure)
clang-tidy -p build src/main.cpp
clang-tidy -p build --fix src/main.cpp # auto-fix what it can
# clang-format (https://clang.llvm.org/docs/ClangFormat.html)
clang-format -style=llvm -dump-config > .clang-format
clang-format -i src/**/*.cpp src/**/*.hpp # format all files
# ast-grep — structural search (AST-aware, not text)
sg -p 'new $$$' --lang cpp # all raw new
sg -p 'NULL' -r 'nullptr' --lang cpp -i # replace all NULLs with nullptrFull pro reference with thread control, reverse debugging & cross-platform crash dumps: debugging-profiling.md Debuggers: GDB, LLDB, raddebugger, x64dbg Profiler: Tracy, Perfetto, Valgrind
gdb -tui ./myapp
# b main | r | n | s | c | p var | bt | bt full | watch var | layout split | thread apply all btLLDB (preferred on macOS/iOS — ships with Xcode)
lldb ./myapp
# b main | run | next | step | continue | print var | po obj | bt | frame variable | expr myFunc(42)Did you know? You can freeze all threads except one. This is HUGE for multithreaded apps.
# GDB — freeze all threads except current
info threads # list threads
thread 3 # switch to thread 3
set scheduler-locking on # NOW only YOUR thread steps
n # next — only thread 3 moves
s # step — only thread 3 moves
set scheduler-locking off # resume all
# LLDB — same concept
thread list # list threads
thread select 3 # switch to thread 3
settings set target.process.stop-others true # freeze others during step
next # only thread 3 moves
settings set target.process.stop-others falseDid you know? GDB can record execution and replay it backwards. Find "how did we get here?"
# GDB — record & reverse
(gdb) target record-full # start recording EVERY instruction
(gdb) continue # run forward normally
# ... hit breakpoint or crash ...
(gdb) reverse-step # step BACKWARDS
(gdb) reverse-continue # run backwards to previous breakpoint
(gdb) reverse-next # next line, backwardsFull cross-platform reference: debugging-profiling.md — Crash Dump section
⚠️ Always provide the target binary! Without it, no symbols resolve = raw hex addresses.
# Windows — LLDB (exe as target, dump as core — BOTH required!)
lldb myapp.exe -c crash.dmp
(lldb) bt # backtrace at crash
(lldb) bt all # all threads
(lldb) frame variable # locals
# Windows — WinDbg for deeper analysis (auto-finds exe from dump)
windbg -z crash.dmp
.sympath+ C:\path\to\pdbs # add YOUR PDBs!
!analyze -v # auto-analysis
kb # call stack with params
# Linux — GDB core dump (binary + core — BOTH required!)
gdb ./myapp core.12345
(gdb) bt full # backtrace + locals
(gdb) thread apply all bt full # all threads
# Linux — coredumpctl (systemd — auto-finds binary + core)
coredumpctl list # captured cores
coredumpctl gdb <pid> # opens GDB with correct binary + core
# Linux — LLDB (binary + core — BOTH required!)
lldb ./myapp -c core.12345
(lldb) bt
# macOS — crash report (binary + report — BOTH required!)
lldb ./MyApp -c MyApp-2024-01-15.ips
(lldb) bt
# Android — tombstone symbolication (unstripped .so path is critical!)
adb logcat | ndk-stack -sym obj/local/arm64-v8a
# iOS — symbolicate crash log (dSYM is critical!)
xcrun symbolicatecrash crash.ips MyApp.app.dSYM > symbolicated.crash| Platform | Dump | Symbols | Binary needed | Tool |
|---|---|---|---|---|
| Windows | .dmp |
.pdb (MANDATORY) |
.exe (MANDATORY) |
LLDB, WinDbg, cdb |
| Linux | core |
unstripped binary / .debug |
ELF binary | GDB, LLDB, coredumpctl |
| macOS | .crash / .ips |
.dSYM/ (MANDATORY) |
Mach-O binary | LLDB, atos |
| iOS | .ips |
.dSYM/ (MANDATORY) |
.app binary |
symbolicatecrash, LLDB |
| Android | tombstone |
unstripped .so (MANDATORY) |
.so files |
ndk-stack, addr2line, LLDB |
Sanitizers (ASan/UBSan/TSan docs)
cmake -B build -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer" -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined"#include <Tracy.hpp>
void heavy() { ZoneScoped; TracyPlot("dt", dt); FrameMark; }tracy-profiler & ./build/dev/myapp # GUI connects automatically- LLDB remote for iOS/Android NDK → mobile.md
- WinDbg kernel debug, crash dumps → reverse-engineering.md
- raddebugger — fast native Windows debugger by Epic
- x64dbg — runtime debugger for stripped binaries
- Valgrind —
valgrind --leak-check=full ./myappfor memory leaks (Linux)
Full reference with tcpdump, Wireshark, DNS, TLS decryption: network-debugging.md Tools: tcpdump, Wireshark, curl, netcat
# Step 1: Can I reach the host?
ping -c 4 host.com # by name
ping -c 4 1.2.3.4 # by IP (bypasses DNS)
# Step 2: Is DNS working?
dig host.com # DNS lookup (Linux/macOS)
nslookup host.com # all platforms
# Step 3: Is the port open?
nc -zv host.com 443 -w 3 # TCP connect test
# PowerShell:
Test-NetConnection host.com -Port 443
# Step 4: What's the route?
traceroute host.com # Linux/macOS
tracert host.com # Windows# tcpdump — capture everything on a port
sudo tcpdump -i any port 8080 -w capture.pcap
# Open capture.pcap in Wireshark
# Filter by host + save
sudo tcpdump -i any -w capture.pcap host api.example.com
# Show only connection attempts (SYN) and refusals (RST)
sudo tcpdump -i any 'tcp[tcpflags] & (tcp-syn|tcp-rst) != 0'
# DNS queries only
sudo tcpdump -i any port 53# Set SSLKEYLOGFILE before running your app
export SSLKEYLOGFILE=~/sslkeys.log
curl https://api.example.com # or run your app
# In Wireshark: Preferences → Protocols → TLS → set key log file
# Now you see decrypted HTTP content!curl -o /dev/null -w "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nFirst byte: %{time_starttransfer}s\nTotal: %{time_total}s\n" https://api.example.com
# If DNS is slow → check /etc/resolv.conf
# If Connect is slow → firewall or routing issue
# If TLS is slow → certificate chain too long
# If First byte is slow → server-side processing# /etc/hosts — redirect domain to localhost
sudo sh -c 'echo "127.0.0.1 api.example.com" >> /etc/hosts'
# Or without modifying hosts:
curl --resolve api.example.com:443:127.0.0.1 https://api.example.comFull reference: cross-compilation.md Cross-compiler: Zig — one tool, every target Emulator: QEMU — test Linux ARM/ARM64 binaries on any host
# Zig — one-command cross-compile
zig c++ -target x86_64-linux-gnu -O2 main.cpp -o main_linux
zig c++ -target aarch64-linux-gnu -O2 main.cpp -o main_arm
zig c++ -target x86_64-macos-none -O2 main.cpp -o main_mac
# Test with QEMU
qemu-x86_64 ./main_linux
qemu-x86_64 -strace ./main_linux # trace syscalls
# CMake + Zig toolchain
cmake -B build/linux -DCMAKE_TOOLCHAIN_FILE=zig-toolchain.cmake -G NinjaFull reference: cmake-package-managers.md Managers: vcpkg, Conan, CPM.cmake
# vcpkg (install: scoop install vcpkg / brew install vcpkg)
cmake -B build -DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
vcpkg install fmt spdlog nlohmann-json # classic mode
# Conan 2 (install: pip install conan)
conan install . --output-folder=build --build=missing
cmake -B build -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmakeFull reference: justfile.md Tool: just — like Make but without the pain
# justfile
default:
@just --list
build preset="dev":
cmake --preset {{preset}}
cmake --build --preset {{preset}}
test preset="dev":
ctest --preset {{preset}} --output-on-failure
watch preset="dev":
watchexec -e cpp,hpp,h,c,cmake,just -- just build {{preset}}
lint:
cppcheck --enable=all --suppress=missingIncludeSystem src/
format:
clang-format -i src/**/*.cpp src/**/*.hpp
todos:
rg "TODO|FIXME|HACK|XXX" --type cpp -njust build preset=clang
just watch
just todosFull reference: benchmarking.md Tool: hyperfine — statistical CLI benchmarking
# Basic
hyperfine --warmup 5 --min-runs 20 "./myapp"
# Compare two versions
hyperfine "./old" "./new"
# Parameter sweep
hyperfine -P size 1024 65536 "./myapp --buf {size}"
# Compilation benchmark
hyperfine --prepare 'rm -rf build && cmake -B build -G Ninja' 'cmake --build build'What files did that command/exe actually produce?
# strace — trace all file opens/writes (https://strace.io)
strace -f -e trace=open,openat,write -o trace.log ./myapp
strace -f -e trace=openat ./myapp 2>&1 | grep "O_CREAT" # only new files
# macOS — fs_usage (built-in, comprehensive)
fs_usage -f filesys ./myapp
# Quick before/after snapshot
touch marker && ./myapp && find . -newer marker -type f# procmon — GUI file/registry/network tracker ([Sysinternals](https://learn.microsoft.com/en-us/sysinternals/))
procmon /Quiet /Minimized /BackingFile trace.pml /AcceptEula
./myapp.exe
procmon /Terminate
procmon /OpenLog trace.pml /SaveAs trace.csv
# drstrace — CLI syscall tracing
scoop install drmemory
drstrace -- myapp.exe # → drstrace.myapp.exe.PID.log| Command | Produces | Where |
|---|---|---|
cmake -B build |
CMakeCache.txt, build.ninja |
build/ |
cmake --build build |
.o, .a, .exe, .so, .dylib |
build/ |
clang-tidy --fix |
Modified .cpp (in-place) |
source tree |
clang-format -i |
Modified .cpp (in-place) |
source tree |
upx --best app |
Compressed binary (in-place) | same path |
strip app |
Stripped binary (in-place) | same path |
rgp capture |
*.rgp GPU trace |
specified path |
tracy-profiler |
*.tracy capture |
current dir |
doxygen |
html/, latex/ |
docs/ or configured |
Full reference: mobile.md Android: ADB docs, Android NDK iOS: devicectl, xcrun
# Install: scoop install adb / brew install android-platform-tools
adb devices -l # list devices
adb install -r app.apk # install/reinstall
adb logcat -s MyTag *:E # filtered errors
# Root (eng/userdebug builds or [Magisk](https://topjohnwu.github.io/Magisk/))
adb root # restart adbd as root
adb shell setenforce 0 # disable SELinux
adb shell getenforce # check: Enforcing/Permissive
# Google APIs image (no Play Services — for clean testing)
sdkmanager "system-images;android-34;google_apis;arm64-v8a"
emulator -avd pixel_test -writable-system -no-snapshotiOS (macOS only — requires Xcode)
xcrun simctl list devices # list simulators
xcrun simctl boot "iPhone 15" # boot one
xcrun simctl install booted MyApp.app # install
xcrun simctl io booted screenshot screen.png
# Physical device (Xcode 15+)
xcrun devicectl list devices
xcrun devicectl device install app --device <id> MyApp.app
# Build
xcodebuild -project MyApp.xcodeproj -scheme MyApp -sdk iphonesimulator build
# LLDB remote debug
lldb -n MyAppFull reference: reverse-engineering.md Tools: Ghidra (NSA decompiler), radare2 (RE framework), x64dbg (Windows debugger), WinDbg (kernel debug), IDA
# Quick recon
file myapp # ELF/PE/Mach-O?
checksec --file=myapp # ASLR, DEP, PIE, canary?
strings myapp | rg -i "password|secret|key|token"
# Ghidra — decompile to C
ghidra # launch GUI
# F5 = decompile | L = rename | X = cross-refs | G = go to address
# radare2 — CLI RE
r2 -A myapp # open + full analyze
# afl = functions | iz = strings | pdf = disasm | VV = graph | s main = seek to main
# x64dbg — Windows runtime debug
x64dbg myapp.exe
# F2 = breakpoint | F7 = step in | F8 = step over | F9 = run
# WinDbg — kernel debug + crash dumps
windbg -z crash.dmp
# !analyze -v | kb | lm | .sympath srv*https://msdl.microsoft.com/download/symbols
# Binary patching (r2)
oo+ # reopen in write mode
wa nop @ 0x401000 # NOP out instructionFull reference: binary-tools.md Tools: UPX, pe-bear, ImHex
# Compress
strip myapp.exe && upx --best myapp.exe
# DLL/dylib/so dependencies
depends myapp.exe # Windows ([dependencywalker.com](https://www.dependencywalker.com))
ldd myapp # Linux (built-in)
otool -L myapp # macOS (built-in)
# PE/ELF inspection
pe-bear myapp.exe # Windows PE viewer
readelf -h myapp # ELF header
objdump -h myapp.exe # PE sections
# Strings audit
strings myapp.exe | rg -i "password|secret|pdb"
# Pre-ship checklist
checksec --file=myapp # security flags
strings myapp | rg "\.pdb" # debug symbols leaked?
strings myapp | rg -i "password" # secrets?
depends myapp.exe # missing DLLs?Full reference: controls.md Source: Valve Steam Input docs, ISteamInput API, Steamworks
- On-screen icons match device — detect controller type, swap glyphs at runtime
- Cursor matches device — visible for mouse, hidden for gamepad
- All devices work 100% — test disconnect/reconnect, Steam Remote Play
- All inputs navigate menus — d-pad, stick, mouse all traverse UI
- Disconnect → pause — single player pause, multiplayer mark disconnected
Bonus: Gamepad + mouse must work simultaneously — #1 cause of Steam Input compatibility issues.
// Steam Input API — get real controller type for correct glyphs
SteamInput()->Init();
SteamInput()->RunFrame();
InputHandle_t ctrl = SteamInput()->GetControllerForGamepadIndex(0);
EInputActionOrigin origin = SteamInput()->GetActionOriginFromXboxOrigin(ctrl, k_EXboxOrigin_A);
const char* glyph = SteamInput()->GetGlyphForActionOrigin(origin);
// Load glyph as texture → future-proof for any new controllerCritical: Camera/aim action type MUST be
absolute_mousein IGA file. Steam Input converts gyro/trackpad/stick →absolute_mouse. Cannot convert back fromjoystick_move.
Full reference: windows-cpp.md — Dev Mode, WSL, Terminal, PowerToys, compilers, CRT, PDB
# Static CRT (no vcruntime.dll dependency)
cmake -B build -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreaded$<$<CONFIG:Debug>:Debug>"
# PDB in release (crash dumps work — without PDB, crash analysis is impossible)
cmake -B build -DCMAKE_CXX_FLAGS_RELEASE="/Zi" -DCMAKE_EXE_LINKER_FLAGS_RELEASE="/DEBUG /OPT:REF /OPT:ICF"# Defender exclusion for build dirs (admin — massive speedup)
Add-MpPreference -ExclusionPath "C:\Users\YOU\projects"
# Long paths (admin — fixes deep build tree issues)
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" `
-Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force
# Enable Developer Mode (admin — unlocks symlinks, WSL, sideloading)
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
# Install WSL
wsl --install
# Install Windows Terminal (scoop — NOT from Store)
scoop install windows-terminal
# Install PowerToys
scoop install powertoys
# Install coreutils (Unix tools in PowerShell)
scoop install uutils-coreutils| Shortcut | Action |
|---|---|
| Win + X, I | Open Terminal fast |
| Win + X, A | Terminal as Admin |
| Alt + Space | PowerToys Run (launcher) |
| Win + Shift + C | Color Picker |
| Compiler | Best for |
|---|---|
MSVC (cl) |
Production, best PDB, Visual Studio integration |
| Clang-cl | Sanitizers, clang-tidy, cross-platform parity |
| GCC (MSYS2) | POSIX APIs, autotools compat |
Full reference with all links: resources.md
| Book | Author | Focus |
|---|---|---|
| Professional CMake | Craig Scott | CMake definitive guide |
| C++ Best Practices | Jason Turner | 45+ actionable rules |
| Game Engine Architecture | Jason Gregory | Engine design (Naughty Dog) |
| Practical Reverse Engineering | Dang et al. | RE for x86/ARM/Windows |
| Optimized C++ | Kurt Guntheroth | Performance patterns |
| Channel | Focus |
|---|---|
| C++ Weekly (Jason Turner) | 600+ weekly C++ episodes |
| The Cherno | Game engine dev, C++ deep dives |
| CppCon | Annual conference, 300+ talks |
| LiveOverflow | Binary exploitation, RE |
| GDC | Game dev conference talks |
| GPUOpen | AMD GPU tools, Radeon profiling |
| Resource | Link |
|---|---|
| C++ reference | en.cppreference.com |
| Compiler Explorer | godbolt.org |
| C++ Core Guidelines | isocpp.github.io/CppCoreGuidelines |
| Modern CMake | cliutils.gitlab.io/modern-cmake |
| Steamworks | partner.steamgames.com/doc |
| Ghidra | ghidra-sre.org |
Full reference: usb-c-gamedev.md Covers: SDL3 gamepad hotplug, DisplayPort Alt Mode, Power Delivery, USB analysis, docks, cables
scoop install sdl3 # 🪟 Windows
brew install sdl3 # 🍎 macOS
sudo apt install libsdl3-dev # 🐧 Ubuntu/Debian
epm install libSDL3-devel # 🐧 ALT Linuxfind_package(SDL3 REQUIRED)
target_link_libraries(mygame PRIVATE SDL3::SDL3)SDL_Gamepad* gp = nullptr;
// In event loop:
case SDL_EVENT_GAMEPAD_ADDED: gp = SDL_OpenGamepad(event.gdevice.which); break;
case SDL_EVENT_GAMEPAD_REMOVED: SDL_CloseGamepad(gp); gp = nullptr; break;
// Per-frame:
SDL_GetGamepadButton(gp, SDL_GAMEPAD_BUTTON_SOUTH); // A/Cross
SDL_GetGamepadAxis(gp, SDL_GAMEPAD_AXIS_LEFTX); // left stick X
SDL_RumbleGamepad(gp, low, high, ms); # vibration
SDL_GetPowerInfo(&secs, &pct); # battery %lsusb -tv # 🐧 Linux — full USB tree
system_profiler SPUSBDataType # 🍎 macOS
Get-PnpDevice -Class USB # 🪟 Windows PowerShell| Device | DP Output | PD Charging | Cable Needed |
|---|---|---|---|
| Steam Deck | DP 1.4 Alt Mode | 45W | USB 3.2+ |
| ROG Ally | DP Alt Mode | 100W (need 100W PSU) | USB 3.2+ |
| Switch / Switch 2 | HDMI via dock | 18-20W / 100W | Official dock |
Tip: USB-C cable that costs $3 is USB 2.0 charge-only. No video, no fast data. Need USB 3.2+ ($15-25) for DP Alt Mode.
INSTALL: scoop install ripgrep fd bat fzf just cmake ninja ccache llvm zig lazygit
WIN SETUP: reg add DevMode + wsl --install + scoop install windows-terminal powertoys
TERMINAL: Win+X,I (fast open) | Win+X,A (admin) | scoop install windows-terminal (not Store)
POWERTOYS: Alt+Space (Run) | Win+Shift+C (Color) | Win+Ctrl+T (Always on Top)
COREUTILS: scoop install uutils-coreutils wget curl jq tree sed grep openssh
BUILD: cmake -B build -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON && cmake --build build
TARGETS: cmake --build build --target help | sort
FEATURES: cmake -B build -LAH | rg -i "feature|enable|option"
GRAPH: cmake -B build --graphviz=deps.dot && dot -Tpng deps.dot -o deps.png
PROFILE: cmake -B build --profiling-output=prof.json --profiling-format=google-trace
TRACE: cmake -B build --trace-expand 2>&1 | tee trace.log
LAZYGIT: lazygit (visual rebase, cherry-pick, bisect)
REBASE: git rebase -i HEAD~5 (or lazygit: [3] → 'e'/'s'/'d')
BISECT: git bisect start HEAD v1.0 && git bisect run cmake --build build && ctest
WORKTREE: git worktree add ../hotfix hotfix-branch
PROC_SUB: diff <(cmd1 | sort) <(cmd2 | sort) (compare outputs, no temp files)
PARALLEL: fd -e cpp | xargs -P 8 -I {} clang-format -i {}
WATCH: watchexec -e cpp,hpp -- cmake --build build
SEARCH: rg "pattern" --type cpp -n -C 3
FIND: fd -e cpp -e hpp
TODOS: rg "TODO|FIXME|HACK" --type cpp -C 2
BLAME: git blame src/file.cpp | bat -l gitblame
HISTORY: git log -S "functionName" --oneline
HOT FILES: git log --format=format: --name-only --since="6 months ago" | sort | uniq -c | sort -rn | head -15
DIFF: git diff main...HEAD --stat
BENCH: hyperfine --warmup 5 --min-runs 20 "./myapp"
LINT: cppcheck --enable=all --suppress=missingIncludeSystem src/
FORMAT: clang-format -i src/**/*.cpp src/**/*.hpp
PROFILE: tracy-profiler & ./myapp
DEBUG: gdb -tui ./myapp | lldb ./myapp
THREADS: set scheduler-locking on (GDB: freeze all threads except current)
REVERSE: target record-full → reverse-step (GDB: step BACKWARDS in time)
WIN DUMP: lldb myapp.exe -c crash.dmp → bt (LLDB: exe + dump + PDB all needed!)
WIN DUMP: windbg -z crash.dmp → !analyze -v (WinDbg: add .sympath+ for YOUR PDBs)
LNX DUMP: gdb ./myapp core → bt full (GDB: binary + core both needed!)
LNX DUMP: coredumpctl gdb <pid> (systemd: auto-finds binary + core)
MAC DUMP: lldb ./MyApp -c App.ips → bt (LLDB: binary + report both needed!)
IOS DUMP: xcrun symbolicatecrash crash.ips App.dSYM (iOS: dSYM MANDATORY)
AND DUMP: ndk-stack -sym obj/local/arm64-v8a < tombstone (Android: unstripped .so MANDATORY)
SYMBOLS: Archive PDB/dSYM/.debug + binary per release — no symbols = raw hex, useless!
NETWORK: nc -zv host 443 -w 3 (is port open?)
CAPTURE: sudo tcpdump -i any port 8080 -w cap.pcap
TLS DEBUG: export SSLKEYLOGFILE=~/sslkeys.log → Wireshark decrypts HTTPS
CURL TIME: curl -o /dev/null -w "%{time_total}s\n" https://host
CACHE: ccache -s
COMPILEDB: cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON && ln -sf build/compile_commands.json .
STRACE: strace -f -e trace=openat ./myapp | drstrace -- myapp.exe
TRACK: touch marker && ./myapp && find . -newer marker -type f
GPU: rgp capture --output frames.rgp --app myapp --frame 42
ANDROID: adb devices -l && adb install -r app.apk && adb logcat -s Tag
IOS: xcrun simctl boot "iPhone 15" && xcrun simctl install booted App.app
RE: r2 -A myapp | ghidra | x64dbg myapp.exe
CHECKSEC: checksec --file=myapp
SHIP: strip app && upx --best app && depends app && strings app | rg pdb
STEAM: SteamInput()->Init() + GetGlyphForActionOrigin() → future-proof glyphs
CROSS: zig c++ -target x86_64-linux-gnu -O2 main.cpp -o main_linux
LOC: scc src/
AI STUDY: aider --read-only src/engine/ (ask questions about code)
SDL3: scoop install sdl3 | apt install libsdl3-dev | epm install libSDL3-devel
GAMEPAD: SDL_EVENT_GAMEPAD_ADDED → SDL_OpenGamepad() → SDL_GetGamepadButton/Axis
RUMBLE: SDL_RumbleGamepad(gp, low, high, ms)
BATTERY: SDL_GetPowerInfo(&secs, &pct) → SDL_POWERSTATE_ON_BATTERY / CHARGING
USB LIST: lsusb -tv | system_profiler SPUSBDataType | Get-PnpDevice -Class USB
USB VID: 0x045e=Xbox 0x054c=Sony 0x057e=Nintendo 0x28de=Valve
DP ALT: USB-C → dock → HDMI/DP (need USB 3.2+ cable, not $3 charge cable)
PD: Deck=45W | Ally=100W | Switch=18W | EPR=240W
WSL: wsl --install → sudo apt install build-essential cmake gdb lldb clang
CLONE REPO ──► scc + tree + bat README ──► git shortlog + log (orient)
│
WRITE CODE ──► lazygit commit ─────────► cppcheck + clang-tidy (analyze)
│ │
▼ ▼
gdb / lldb sanitizers (ASAN/UBSAN)
set scheduler-locking on thread isolation
target record-full reverse debugging
│ │
└──────────┬─────────────────┘
▼
tracy profile (CPU) | RGP profile (GPU)
▼
hyperfine bench
│
┌──────────────┼──────────────┐
▼ ▼ ▼
cross-compile strace/tcpdump ship
Zig/QEMU (trace files, checksec + strip + UPX
ADB deploy packets, depends/ldd check
xcrun deploy network, TLS) strings secret scan
│ Steam Input (IGA)
▼ Big Picture mode
git bisect (find the regression)
▼
Ghidra/r2/x64dbg (when you need to go deeper)
▼
💀 crash dump analysis (BINARY + SYMBOLS + DUMP)
Win: lldb myapp.exe -c crash.dmp / windbg !analyze -v
Lnx: gdb ./app core / coredumpctl gdb
Mac: lldb ./App -c App.ips / symbolicatecrash
And: ndk-stack -sym obj/local/arm64-v8a
iOS: xcrun symbolicatecrash + dSYM
▼
USB-C: lsusb + SDL3 gamepad test + dock DP output
Companion deep-dives linked inline throughout. Install via scoop, apt, epm, or brew.