Files
voice-cat/docs/building.md
Talon bcb7ae8ccb build(cmake): clean up presets, add release/apple presets, cross-platform triplets
Rationalize the preset set to match the project's actual state (past M5):
- Rename dev->skeleton (no-deps stub smoke), m1-dev->dev (default dev preset)
- Drop m2-dev (cache-identical to m1-dev)
- Add release preset (optimized + tests on, symbols kept)
- Strip server-release binaries (-s linker flag)
- Add apple-dev/apple-ios/apple-ios-sim scaffolding presets for XCFramework

Add cmake/voicecat-toolchain.cmake wrapper that auto-resolves the vcpkg
triplet from the host platform (x64-mingw-static/x64-linux/arm64-osx) so
the main presets work on Windows/Linux/macOS without per-OS variants.

Update all docs (building.md, CLAUDE.md, README.md, AGENTS.md, deployment.md,
tech-stack.md, client READMEs) and stale preset-name references in code
comments. No C++ behavior changes — the core was already portable.
2026-06-18 03:16:01 +02:00

11 KiB

Building & Manual Testing

This doc explains what each CMake preset in CMakePresets.json is for, which one to actually use day-to-day, and the commands to stand up a real server + vccli clients against each other for manual testing. For the one-paragraph quick-start see CLAUDE.md; for ctest targets see AGENTS.md. This doc is the missing middle: how the presets relate to each other, which platform each targets, and how to drive the binaries by hand.

1. What each preset is for

Preset Binary dir Deps Build type Server Tools Tests Strip Platform What it's for
vcpkg-common vcpkg all Hidden base. Sets the vcpkg toolchain wrapper (cmake/voicecat-toolchain.cmake) which auto-resolves the triplet from the host platform. Not used directly.
skeleton build/skeleton none Debug ON ON ON no all The M0 skeleton. Compiles with just a C++20 compiler — no VCPKG_ROOT needed. Subsystems are stubs (VC_ERR_NOT_IMPLEMENTED). Good for "does the repo even build" sanity checks. Runs 2 tests (smoke + frame_codec).
dev build/dev vcpkg Debug ON ON ON no all The one you actually want. Day-to-day development: real protocol, crypto, voice, server — everything. Builds server + tools + tests (21 tests). Works on Windows, Linux, and macOS (triplet auto-resolved).
release build/release vcpkg Release ON ON ON no all Optimized build with the full test suite. Use to run tests against optimized code, profile, or catch optimizer-sensitive bugs. Symbols kept (not stripped) so stack traces and profiling remain useful.
server-release build/server-release vcpkg Release ON ON OFF yes all Production-shaped build for deployment. Optimized + stripped binaries (-s), no tests. This is what you'd ship/run — see docs/deployment.md.
windows-client build/windows-client vcpkg Release OFF OFF OFF no Windows Produces a redistributable voicecat.dll for the C# WinForms client (M4). Static MinGW runtime — no libgcc_s_seh-1.dll etc. See clients/windows/README.md.
apple-dev build/apple-dev vcpkg Release OFF OFF OFF no macOS Scaffolding — static libvoicecat.a for the Swift Package / XCFramework (macOS slice). Not yet CI-validated; build on macOS to verify. See clients/apple/README.md.
apple-ios build/apple-ios vcpkg Release OFF OFF OFF no macOS→iOS Scaffolding — cross-compiled static libvoicecat.a for iOS device (arm64-ios). One XCFramework slice. Not yet CI-validated.
apple-ios-sim build/apple-ios-sim vcpkg Release OFF OFF OFF no macOS→iOS sim Scaffolding — cross-compiled static libvoicecat.a for iOS simulator (arm64-ios-sim). One XCFramework slice. Not yet CI-validated.

So in practice there are three presets that matter for day-to-day work:

  • dev — everything: real protocol, real voice, real manual testing. This is the loop you run constantly.
  • release — same suite, optimized. Run it when you want to check optimized behavior or profile.
  • skeleton — fast no-deps build to confirm the stub path still compiles (CI smoke check).

The rest are purpose-specific: server-release for deployment, windows-client for the DLL, apple-* for Apple platform slices.

Platform matrix

The vcpkg presets (dev, release, server-release, windows-client, apple-*) auto-resolve the vcpkg triplet via cmake/voicecat-toolchain.cmake:

Host platform Auto-resolved triplet Notes
Windows (MinGW/MSYS2) x64-mingw-static The project's Windows toolchain. MSVC users must set VCPKG_TARGET_TRIPLET=x64-windows explicitly.
Linux x64 x64-linux Server's primary deployment target (Docker, systemd).
Linux arm64 arm64-linux Raspberry Pi / ARM VPS.
macOS (Apple Silicon) arm64-osx apple-dev uses this automatically.
macOS (Intel) x64-osx apple-dev uses this automatically.

Cross-compile presets (apple-ios, apple-ios-sim) override VCPKG_TARGET_TRIPLET explicitly; VCPKG_HOST_TRIPLET stays the host's (e.g. arm64-osx when building iOS on Apple Silicon).

Preset history

The preset set was cleaned up on 2026-06-18 (see PROGRESS.md). The old names map as follows:

Old name New name Notes
dev skeleton Renamed to reflect its actual purpose (no-deps stub smoke check).
m1-dev dev Renamed — the project is past M5, so milestone-named presets were misleading. This is now the default development preset.
m2-dev (dropped) Was cache-identical to m1-dev (same flags, same triplet, only the binary dir differed). Removed.
server-release server-release Unchanged name; now stripped (-s) and auto-triplet.
(new) release New: optimized build with tests on, symbols kept.
windows-client windows-client Unchanged name; triplet now auto-resolved.
(new) apple-dev, apple-ios, apple-ios-sim New: Apple platform scaffolding.

If you see m1-dev or m2-dev in old scripts, commits, or PROGRESS.md history entries, use dev instead. Historical PROGRESS.md entries are left intact as a true record of what was run.

2. One-time setup for the real-deps presets

dev, release, server-release, windows-client, and apple-* all need VCPKG_ROOT pointing at a bootstrapped vcpkg checkout:

# once:
git clone https://github.com/microsoft/vcpkg
./vcpkg/bootstrap-vcpkg.sh        # .bat on Windows

# every shell session (PowerShell):
$env:VCPKG_ROOT = "D:\path\to\vcpkg"

# or on Linux/macOS:
export VCPKG_ROOT=/path/to/vcpkg

vcpkg.json (manifest mode) pins every dependency (protobuf, mbedTLS, libsodium, asio, sqlite3, spdlog, opus, miniaudio) — cmake --preset dev resolves and builds them automatically on first configure. That first configure is slow (vcpkg building from source); subsequent ones are cached.

3. Build + test (the loop you'll run constantly)

cmake --preset dev
cmake --build --preset dev
ctest --preset dev

Binaries land in build/dev/bin/ (.exe suffix on Windows):

  • build/dev/bin/voicecat-server
  • build/dev/bin/vccli
  • build/dev/bin/voicecat-admin

To run the same suite against optimized code:

cmake --preset release
cmake --build --preset release
ctest --preset release

4. Manual testing: server + two clients

Start the server

./build/dev/bin/voicecat-server --name "Test Server" --data-dir ./voicecat-data

First run generates an Ed25519 identity + self-signed cert under --data-dir, creates the SQLite store, and creates a default "Lobby" channel. Other server flags:

--port <n>          control+media port (default 8384)
--data-dir <path>   data directory (default ./voicecat-data)
--name <name>       server name
--no-guests         disable guest access (then provision accounts via voicecat-admin)
--print-config      print effective config and exit
--version           print version and exit

Drive it with vccli

vccli is the headless client used to exercise the protocol by hand. Full flag list:

vccli [--host H] [--port P] [--nick NAME] [--channel ID]
      [--voice] [--mute] [--text MSG] [--list-devices]
      [--input-device ID] [--input-mode vad|ptt] [--share-screen-audio]

  --host H              server host (default 127.0.0.1)
  --port P              server TCP port (default 8384)
  --nick NAME           guest nickname (default vccli-test)
  --channel ID          channel to join after auth (default 1, Lobby)
  --voice               start a MIC stream and stay connected until Ctrl+C
  --mute                start with the mic muted (only meaningful with --voice)
  --text MSG            send MSG to the channel, then exit
  --list-devices        print input/output devices (vc_list_devices) and exit
  --input-device ID     use device ID (from --list-devices) for the MIC stream
  --input-mode vad|ptt  send-side input gate mode (default vad)
  --share-screen-audio  also start a SCREEN_AUDIO stream (WASAPI loopback on Windows)

While --voice is running, stdin accepts ptt on, ptt off, mode vad, mode ptt to toggle the input gate live.

Smoke test — two clients talking:

# terminal A
./build/dev/bin/vccli --nick Alice --text "hello from Alice"

# terminal B (separate window, after A confirms it sent)
./build/dev/bin/vccli --nick Bob --text "hello from Bob"

Real voice between two clients (needs working mic/speakers, two terminals):

# terminal A
./build/dev/bin/vccli --nick Alice --voice

# terminal B
./build/dev/bin/vccli --nick Bob --voice

Speak into the mic on one side; you should hear it on the other. Ctrl+C to disconnect.

Enumerate audio devices before picking one:

./build/dev/bin/vccli --list-devices
./build/dev/bin/vccli --nick Alice --voice --input-device <ID> --input-mode ptt

Provisioning a non-guest account (if the server was started with --no-guests):

./build/dev/bin/voicecat-admin --data-dir ./voicecat-data account add alice --password secret
./build/dev/bin/voicecat-admin --data-dir ./voicecat-data account list

5. server-release (production-shaped build)

Same dependency story, but Release build type, stripped binaries, and no tests — this is the closest local analogue to what docs/deployment.md's "from source" path produces:

cmake --preset server-release
cmake --build --preset server-release
./build/server-release/bin/voicecat-server

Use this to sanity-check release-mode behavior (e.g. perf, optimized codepaths) — not for day-to-day development, since it has no test target wired up. The -s linker flag strips symbol tables from the binaries, producing smaller executables suitable for distribution.

6. Apple platform builds (scaffolding)

The apple-dev, apple-ios, and apple-ios-sim presets produce static libvoicecat.a slices for the Swift Package / XCFramework. They are scaffolding — not yet CI-validated and won't build on Windows. Build on macOS:

# macOS slice (arm64-osx on Apple Silicon, x64-osx on Intel)
cmake --preset apple-dev
cmake --build --preset apple-dev
# → build/apple-dev/lib/libvoicecat.a

# iOS device slice
cmake --preset apple-ios
cmake --build --preset apple-ios
# → build/apple-ios/lib/libvoicecat.a

# iOS simulator slice
cmake --preset apple-ios-sim
cmake --build --preset apple-ios-sim
# → build/apple-ios-sim/lib/libvoicecat.a

The three .a files are then stitched into an XCFramework via xcodebuild -create-xcframework (see clients/apple/README.md for the planned workflow). Actual XCFramework stitching, AVAudioSession integration, and iOS UI work are tracked as follow-up tasks — the presets exist so the build entry point is ready when that work starts.