ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches

πŸ”¨ Compile human-readable code into machine-executable code

πŸ”¨ Compile human-readable code into machine-executable code

CMake Compile README

Overview

ascii-chat uses a highly modular CMake build system designed for cross-platform development across Linux, macOS, and Windows. The build system automatically handles platform differences, dependency management, caching, and optimization for both development and release builds.

Key Features:

  • Modular CMake architecture (30+ specialized modules)
  • Cross-platform support (Linux, macOS, Windows)
  • Automatic dependency caching (ccache, FetchContent)
  • Multiple build types (Debug, Dev, Release, RelWithDebInfo)
  • Coverage instrumentation option (combinable with any build type)
  • Static release builds with musl (Linux only)
  • High-performance allocator (mimalloc) for release builds
  • CMake presets for common configurations
  • Windows build script for convenience

Quick Start

Build and install ascii-chat:

make CMAKE_BUILD_TYPE=RelWithDebInfo && sudo make install

Or use CMake directly with presets:

# List available presets
cmake --list-presets
# Build with a preset (configure + build in one command)
cmake --build --preset release
cmake --build --preset debug
cmake --build --preset dev

Or configure manually:

cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build
sudo cmake --install build

See CMake Presets (Preferred) for all available presets and CMake Configuration Options for configuration options.

Compilation Philosophy

ascii-chat has a few goals to satisfy, and the build system reflects them all.

Development Builds (Dynamic)

First, I need to actually develop ascii-chat for it to exist. Development builds use dynamic linking because it's fasterβ€”shared libraries reduce link time, sanitizers work better, and I can rebuild only what changed. That's why the CMake configuration is complex: it handles both fast development builds and production-ready releases.

Development linking:

  • Windows: Dynamic vcpkg DLLs (x64-windows triplet)
  • Linux: Dynamic .so files against glibc
  • macOS: Dynamic .dylib against system frameworks

Build modes:

  • Debug: Maximum debugging with AddressSanitizer enabled
  • Dev: Fast builds without sanitizer overhead

The Library (libasciichat)

I'm proud of libasciichat and made it available for others to use. That's why we build and distribute a libraryβ€”so you can link against it in your own projects.

Release artifacts include:

  • libasciichat.so / asciichat.dll / libasciichat.dylib - Dynamic library
  • libasciichat.a / asciichat.lib - Static library

We distribute both dynamic and static libraries so you have options. Use the dynamic library for normal development, or use the static library to build your own portable releases.

Static Releases (Portability is Awesome)

Static linking follows the same philosophy as musl and many musl-based projects: portability is awesome.

I compile Linux releases in a VM or Docker container running a distro that end users might not be runningβ€”and the executables still work everywhere. That's cool from both perspectives: as a developer, I can build anywhere; as a user, you can run it anywhere.

Why static?

  • One file: With a static executable, ascii-chat is one file. That's an amazing thing to be able to say about your project in the world of software, especially if it's complex at all.
  • No dependency hell: No DLLs, no .so files, no .dylibsβ€”they're extra files to worry about, version, and distribute. Static linking eliminates all of that.
  • True portability: Works on any Linux distribution, any glibc version, any system configuration.

Platform linking:

  • Linux: Static musl libc with static-PIE (fully self-contained)
  • Windows: Static vcpkg libraries (x64-windows-static triplet)
  • macOS: Currently dynamic (static planned for future releases)

For Your Projects

We distribute a static library (libasciichat.a / asciichat.lib) alongside the dynamic library so that you too can make portable static releases of your project with libasciichat. If you're building something that uses ascii-chat's library and you want a single portable binary, link against the static lib.

Release Distribution

Download binaries: Grab ascii-chat from the GitHub Releases page. Each release ships ready-to-run binaries, installers, and SDK artifacts for Linux, macOS, and Windows.

Build from source: Clone the repository, install the dependencies documented in Dependencies README and the project README, then run make CMAKE_BUILD_TYPE=RelWithDebInfo to produce a working copy in build/bin/.

Summary

Platform Development Production Release Artifacts
Windows DLL (x64-windows) Static (x64-windows-static) .exe, .dll, .lib, .msi installer
Linux .so (glibc) Static (musl) binary, .so, .a, .deb/.rpm
macOS .dylib Static (planned) binary, .dylib, .a, .pkg
Build Mode Optimization Debug Info Sanitizers C Runtime
Debug -O0 Full ASan,UBSan glibc/UCRT/libSystem
Dev -O0 Full None glibc/UCRT/libSystem
Release -O3 None None musl/UCRT(static)/libSystem
RelWithDebInfo -O3 Full None musl/UCRT/libSystem

Build Tool Requirements

This section documents tools needed to build ascii-chat. For library dependencies (zstd, libsodium, PortAudio, etc.), see Dependencies README.

Required Tools

These tools are needed for all builds on all platforms:

Tool Version Purpose
cmake 3.20+ Build system generator
clang 18+ C compiler
clang++ 18+ C++ compiler (for defer/panic tools)
llvm-config 18+ Query LLVM paths (for defer/panic tools)
llvm-ar 18+ Static library archiver
llvm-ranlib 18+ Static library indexer
ninja Any Build system (Ninja is required)
git Any Version detection, dependency patching

Platform-specific required tools:

Platform Additional Required Tools Purpose
Linux pkg-config Dependency detection
macOS pkg-config (Homebrew), xcrun Dependency detection, SDK tools
Windows clang-cl, llvm-lib, nmake BearSSL build (MSVC-compatible tooling)
Note
ascii-chat is a Clang-only project. GCC and MSVC are not supported.
llvm-lib is the LLVM equivalent of Microsoft's lib.exe for creating static libraries.
clang-cl is Clang's MSVC-compatible driver for Windows builds.
nmake is Microsoft's make tool, required for building BearSSL on Windows.

Optional Build Tools

These tools improve the build experience but aren't required:

Tool Purpose When Useful
ccache Compiler cache 5-10x faster rebuilds
clang-format Code formatting format target
clang-tidy Static analysis Required when ASCIICHAT_ENABLE_ANALYZERS=ON
cppcheck Static analysis Additional code checking
doxygen Generate documentation Release packages
bash Shell scripting Required when ASCIICHAT_BUILD_WITH_PANIC=ON
python3 Build scripts Optional scripting support
lld LLVM linker Faster linking, required for USE_MUSL builds
scan-build Static analyzer Clang static analyzer wrapper
Note
Debugging tools (lldb, llvm-symbolizer, addr2line, valgrind, leaks) are documented in Debugging - they are not build tools.

Build Type Additions

All build types share the same required tools. Each type adds specific needs:

Build Type Additional Tools Purpose
Debug (none) Uses same tools as other builds
Dev (none) Fast builds without sanitizers
Release doxygen (optional) Documentation for packages
Coverage (option) llvm-profdata, llvm-cov Generate coverage reports (use -DASCIICHAT_ENABLE_COVERAGE=ON)

Linux static builds (USE_MUSL=ON) additionally require:

  • lld - LLVM linker for static-PIE linking
  • musl-gcc - musl C compiler wrapper
  • gcc - used by musl-gcc via REALGCC environment variable

Package Generators

CPack auto-detects available package generators. All are optional:

Platform Tool Package Format
Linux dpkg-deb .deb (Debian/Ubuntu)
Linux rpmbuild .rpm (Fedora/RHEL)
macOS productbuild .pkg
Windows wix .msi (WiX Toolset v4+)
Windows makensis .exe installer (NSIS)
All tar/zip .tar.gz, .zip

Verifying Your Setup

Quick check that all required tools are available:

# Check LLVM toolchain
clang --version && clang++ --version && llvm-config --version
# Check build tools
cmake --version && ninja --version
# Check archiver tools
llvm-ar --version && llvm-ranlib --version

If any tool is missing, the CMake configure step will fail with a clear error message explaining what to install.

Building Documentation

# Build docs (requires doxygen)
cmake --build build --target docs
# Documentation output
ls build/docs/html/ # HTML documentation
ls build/docs/man/man3/ # Unix manpages
# Build release package (includes documentation)
cmake --build build --target package

Windows Notes

Windows requires bash (from Git Bash, WSL, or MSYS2) for test scripts and the panic tool. Git Bash is recommended - it's bundled with Git for Windows and automatically detected by CMake.

The preferred way to build on Windows is using the PowerShell script:

./build.ps1 # Default build
./build.ps1 -Clean # Clean rebuild
./build.ps1 -Config Release # Release build

CMakeLists.txt Modularity

Modular Architecture

The main CMakeLists.txt is organized as a modular system, with each major aspect handled by a dedicated module in the cmake/ directory:

Note
All file paths listed below are relative to the cmake/ directory.

Root-level Modules:

  • ProjectConstants.cmake - Project metadata (name, author, URLs, license)

Core Configuration Modules (init/):

  • init/Init.cmake - Initial setup and paths
  • init/FindPrograms.cmake - Centralized program discovery (clang, llvm-config, etc.)
  • init/BuildTypes.cmake - Build type configuration (Debug, Release, etc.)
  • init/Options.cmake - Build options (mimalloc, musl, tests, etc.)
  • init/BuildConfiguration.cmake - Build configuration helpers
  • init/PlatformDetection.cmake - Platform-specific variables (Linux, macOS, Windows)

Compiler Configuration (compiler/):

  • compiler/CompilerDetection.cmake - Compiler detection and configuration
  • compiler/CompilerFlags.cmake - Base compiler flags and standards
  • compiler/CCache.cmake - Compiler cache configuration
  • compiler/SIMD.cmake - SIMD instruction detection
  • compiler/CRC32.cmake - Hardware-accelerated CRC32 detection
  • compiler/PCH.cmake - Precompiled headers
  • compiler/LLVM.cmake - LLVM toolchain configuration
  • compiler/HeaderChecks.cmake - Header availability checks
  • compiler/ToolchainChecks.cmake - Toolchain validation

Platform Configuration (platform/):

  • platform/WindowsWorkarounds.cmake - Windows-specific fixes
  • platform/CodeSigning.cmake - macOS code signing for Gatekeeper compatibility
  • platform/Sanitizers.cmake - Sanitizer configuration (ASan, UBSan, etc.)
  • platform/Musl.cmake - musl libc configuration (Linux only)

Dependencies (dependencies/):

  • dependencies/Dependencies.cmake - External dependency finding (main entry point)
  • dependencies/Vcpkg.cmake - vcpkg package manager integration
  • dependencies/BearSSL.cmake - BearSSL TLS library
  • dependencies/Criterion.cmake - Criterion test framework
  • dependencies/Libsodium.cmake - libsodium cryptography library
  • dependencies/Mimalloc.cmake - mimalloc memory allocator
  • dependencies/MuslDependencies.cmake - Static dependency building for musl
  • dependencies/Portaudio.cmake - PortAudio audio library
  • dependencies/Zstd.cmake - Zstandard compression library

Build Targets (targets/):

  • targets/SourceFiles.cmake - Source file collection
  • targets/Libraries.cmake - Library linking
  • targets/Executables.cmake - Executable targets
  • targets/Tests.cmake - Test framework configuration

Installation and Packaging (install/):

  • install/Install.cmake - Installation rules and CPack package generation
  • install/Archive.cmake - Archive package configuration (ZIP, TGZ)
  • install/Deb.cmake - Debian package configuration
  • install/Rpm.cmake - RPM package configuration
  • install/Version.cmake - Version generation
  • install/Documentation.cmake - Doxygen documentation

Testing (test/):

  • test/TestFramework.cmake - Test framework setup

Tooling and Instrumentation (tooling/):

  • tooling/Panic.cmake - Panic instrumentation (per-statement logging for crash debugging)
  • tooling/Defer.cmake - Defer transformation (Go/Zig-style defer statements)
  • tooling/ToolingRuntime.cmake - Builds the runtime that the panic tool needs to work, and also the panic-report tool.

Utilities (utils/):

  • utils/Include.cmake - Include directory configuration
  • utils/PostBuild.cmake - Post-build processing
  • utils/StatusMessages.cmake - Build status output
  • targets/CustomTargets.cmake - Custom build targets (format, clang-tidy, etc.)

CMake Presets (Preferred)

CMake Presets are the preferred way to configure builds. They provide standardized configurations with all the right flags for each build type.

Quick Start

# Configure and build (one command)
cmake --build --preset debug # Debug with sanitizers
cmake --build --preset dev # Fast iteration, no sanitizers
cmake --build --preset release # Optimized for distribution
cmake --build --preset coverage # Code coverage analysis

Available Presets

Preset Build Type Use Case
default / debug Debug Bug hunting with sanitizers
debug-musl Debug Static musl debug (Linux only)
dev Dev Fast daily development
release Release Production builds (static on Linux/Windows)
release-musl Release Force musl static (Linux only)
relwithdebinfo RelWithDebInfo Optimized with debug symbols
coverage Debug + Coverage Debug build with coverage instrumentation

IDE Integration

Presets are defined in CMakePresets.json and work with VS Code, CLion, and other CMake-aware IDEs. Select a preset from your IDE's configuration dropdown to get consistent builds across your team.

Custom Presets

Create custom presets by editing CMakePresets.json:

{
"name": "my-custom",
"displayName": "My Custom Build",
"inherits": "base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"USE_MIMALLOC": "OFF",
"BUILD_TESTS": "ON"
}
}

Build Types

Debug Build

Purpose: Finding bugs, memory issues, undefined behavior

Configuration:

cmake -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build

Features:

  • Optimization: -O0 (no optimization)
  • Debug Symbols: Yes (full backtraces)
  • Sanitizers: ASan, UBSan, LSan, Integer, Nullability
  • mimalloc: Disabled by default (better debugging)
  • musl: Disabled on Linux (use glibc for debugging)

When to Use:

  • Finding crashes
  • Memory leak detection
  • Undefined behavior detection
  • Debugging production issues

Dev Build

Purpose: Fast compilation, daily development

Configuration:

cmake -B build -DCMAKE_BUILD_TYPE=Dev
cmake --build build

Features:

  • Optimization: -O0 (no optimization)
  • Debug Symbols: Yes (full backtraces)
  • Sanitizers: None (faster runtime)
  • mimalloc: Disabled by default
  • musl: Disabled on Linux

When to Use:

  • Fast edit-compile-test cycles
  • Daily development
  • When sanitizer overhead is too slow

Release Build

Purpose: Production deployment, performance testing

Configuration:

# Standard Release (dynamic glibc on Linux)
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
# Static musl Release (Linux only)
cmake -B build -DCMAKE_BUILD_TYPE=Release -DUSE_MUSL=ON
cmake --build build

Features:

  • Optimization: -O3 (maximum optimization)
  • Debug Symbols: No (smaller binaries)
  • Sanitizers: None (maximum performance)
  • mimalloc: Enabled by default
  • musl: Enabled on Linux (for Release/RelWithDebInfo)

Stack Protection: -fstack-protector-strong kept enabled on Unix

  • PIE / ASLR: Enabled on all platforms (Linux static-PIE, macOS -Wl,-pie, Windows /dynamicbase + /highentropyva)
  • Control-Flow Guard (Windows): /guard:cf and /nxcompat enforced when using clang-cl
  • Dead Dylib Stripping (macOS): -Wl,-dead_strip_dylibs removes unused framework deps
  • Interprocedural Optimization: Automatically enabled when the toolchain supports IPO/LTO

Security & Portability Philosophy:

  • Release artefacts must run everywhere: we default to a portable CPU baseline (-march=x86-64 or -march=armv8-a) so a build from a modern workstation still runs on older hosts. Opt-in profiles let you trade reach for throughput when you know your deployment target.
  • Harden first, tune second: stack protectors, NX, ASLR, and CFG stay enabled even when chasing size or perf. They are cheap insurance, so we only let you dial them back after an explicit, auditable choice.
  • Keep crash forensics viable: frame pointers remain on by default, unwind tables are preserved, and we build symbol bundles so answering β€œwhy did it crash?” never requires reproducing the exact build tree.
  • Cross-module performance is intentional: interprocedural optimization (IPO/LTO) now spans the shared library, static SDK archive, and main executable so users linking against the SDK get the same scalar/SIMD inlining the app does. The build automatically falls back when IPO is unsupported.

Configurable Release Knobs:

  • -DASCIICHAT_RELEASE_CPU_TUNE=portable|x86-64-v2|x86-64-v3|native|custom
    • Controls the CPU baseline used for Release compilation.
    • portable (default) prioritizes broad compatibility.
    • x86-64-v2/x86-64-v3 target newer Intel/AMD micro-architectures.
    • native mirrors the build host for lab benchmarking (not portable).
    • custom consumes additional switches from ASCIICHAT_RELEASE_CPU_CUSTOM_FLAGS.
  • -DASCIICHAT_RELEASE_CPU_CUSTOM_FLAGS="-msse4.2 ..."
    • Additional compiler switches applied when ASCIICHAT_RELEASE_CPU_TUNE=custom.
    • Space-separated flags are supported; quote the whole string for the shell.
  • -DASCIICHAT_RELEASE_ENABLE_FAST_MATH=ON
    • Opt-in for the aggressive fast-math bundle (reciprocal approximations, associative FP, etc.).
    • Default is OFF to keep IEEE semantics for audio mixing and crypto code; toggle only after profiling the hot loops you own.
  • -DASCIICHAT_RELEASE_KEEP_FRAME_POINTERS=OFF
    • Lets you trade unwindable stacks for slightly smaller/faster code.
    • Default ON keeps frame pointers so postmortem tooling (Crashpad, addr2line, symbolicators) can reconstruct stacks from field crashes.
  • -DASCIICHAT_CODESIGNING=ON|OFF (macOS only)
    • Enable or disable code signing for Gatekeeper compatibility.
    • Default ON in Release mode, OFF in all other build types.
    • Requires CODESIGNING_IDENTITY to be set (via CMake variable or environment).

The release toolchain prints the resolved choices during configuration. For CI/CD, pin them in your preset so the resulting artefacts are reproducible and reviewers can tell which trade-offs you made.

When to Use:

  • Production deployments
  • Performance benchmarking
  • Creating releases
  • Distributing binaries

RelWithDebInfo Build

Purpose: Optimized build with debug symbols for debugging production issues

Configuration:

cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build

Features:

  • Optimization: -O3 (maximum optimization)
  • Debug Symbols: Yes (full backtraces)
  • Sanitizers: None (performance-critical)
  • mimalloc: Enabled by default
  • musl: Enabled on Linux (for Release/RelWithDebInfo)
  • Errno Backtraces: Enabled (for debugging)
  • PDB Generation (Windows): Enabled with Clang

When to Use:

  • Debugging performance issues
  • Profiling optimized code
  • Production debugging (with symbols)
  • Analyzing crashes from optimized builds

Debug Symbols in Production:

  • Debug symbols included but not stripped
  • Can be stripped later: strip build/bin/ascii-chat
  • Separate debug info can be generated (Linux: .debug file)

Windows PDB Files:

  • PDB (Program Database) files generated with Clang on Windows
  • Enable source-level debugging of optimized code
  • Generated in build/bin/ directory

Coverage Instrumentation (Option)

Purpose: Code coverage analysis

Coverage is an option (ASCIICHAT_ENABLE_COVERAGE) that can be combined with any build type, not a separate build type. This allows you to get coverage data from Debug, Release, or any other build configuration.

Configuration:

# Debug build with coverage (recommended for CI)
cmake -B build -DCMAKE_BUILD_TYPE=Debug -DASCIICHAT_ENABLE_COVERAGE=ON
cmake --build build
# Or use the coverage preset (Debug + coverage)
cmake --preset coverage
cmake --build build
# Release build with coverage (for performance profiling)
cmake -B build -DCMAKE_BUILD_TYPE=Release -DASCIICHAT_ENABLE_COVERAGE=ON
cmake --build build

Features:

  • Coverage Flags: --coverage -fprofile-arcs -ftest-coverage
  • Combinable: Works with Debug, Dev, Release, RelWithDebInfo
  • CI Default: GitHub CI preset enables coverage automatically

Generating Coverage Reports:

# Build with coverage
cmake -B build -DCMAKE_BUILD_TYPE=Debug -DASCIICHAT_ENABLE_COVERAGE=ON
cmake --build build
# Run tests (generates .gcda files)
ctest --test-dir build --output-on-failure
# Generate report (clang)
llvm-cov gcov src/*.c lib/**/*.c
llvm-cov show --format=html --output-dir=coverage-report

When to Use:

  • Measuring test coverage
  • Finding untested code paths
  • Continuous integration coverage reporting

CMake Configuration Options

This section documents all CMake cache variables and options that control the build behavior. Options are set via -D<OPTION>=<VALUE> on the command line.

Core Build Options

Build Type and Testing:

Option Type Default Description
CMAKE_BUILD_TYPE STRING Debug Build configuration (Debug, Dev, Release, RelWithDebInfo)
ASCIICHAT_ENABLE_COVERAGE BOOL OFF Enable coverage instrumentation (can combine with any build type)
BUILD_TESTS BOOL ON Build the Criterion test suite

Memory Allocator Options

Option Type Default Description
USE_MIMALLOC BOOL Auto Enable mimalloc allocator (ON for Release/RelWithDebInfo, OFF otherwise)

C Library Options (Linux Only)

Option Type Default Description
USE_MUSL BOOL Auto Use musl libc for static linking (ON for Release/RelWithDebInfo on Linux)

Tooling and Instrumentation Options

These options enable source-to-source transformations using Clang libTooling. These are debugging tools - use them when you have a crash or bug to investigate.

Option Type Default Description
ASCIICHAT_BUILD_WITH_PANIC BOOL OFF Enable panic instrumentation (per-statement logging for crash debugging)
ASCIICHAT_PANIC_TOOL PATH "" Path to pre-built ascii-instr-panic tool (skips tool rebuild)
ASCIICHAT_DEFER_TOOL PATH "" Path to pre-built ascii-instr-defer tool (skips tool rebuild)

Note: Defer transformation is automatic when source files contain defer() calls. There is no option to enable/disable it - the build system detects defer() usage automatically.

Panic Instrumentation (Crash Debugging)

Panic instrumentation enables per-statement logging for debugging crashes. When the program crashes, the last line printed is the crashing line.

# Build with panic instrumentation
cmake -B build -DASCIICHAT_BUILD_WITH_PANIC=ON
cmake --build build
# Run the program
export ASCII_PANIC_OUTPUT_DIR=/tmp/crash-logs
./build/bin/ascii-chat server
# Find crash location
tail -n1 /tmp/crash-logs/ascii-instr-*.log

For complete documentation, including usage workflows, environment variable filtering, multi-threaded debugging, the ascii-panic-report tool, and the background on why this technique works, see Panic Instrumentation.

Defer Transformation (Automatic)

Defer Transformation:

  • Enables Go/Zig-style defer statements in C code
  • Automatically runs cleanup code at function exit
  • Automatic: Enabled when source files contain defer() - no option needed
  • Outputs transformed sources to build/defer_transformed/
  • See Defer Statements for detailed documentation

Usage Example:

# Build with panic instrumentation (for debugging crashes)
cmake -B build -DASCIICHAT_BUILD_WITH_PANIC=ON
cmake --build build
# Defer transformation is automatic - just build normally
cmake -B build
cmake --build build
# If any source files contain defer(), they are automatically transformed
# Use pre-built tools (faster rebuilds)
cmake -B build -DASCIICHAT_BUILD_WITH_PANIC=ON \
-DASCIICHAT_PANIC_TOOL=/path/to/ascii-instr-panic

Compiler and Build Options

Option Type Default Description
USE_CCACHE BOOL ON Enable ccache compiler cache (auto-disabled for musl)
ASCIICHAT_USE_PCH BOOL ON Enable precompiled headers for faster builds
ASCIICHAT_ENABLE_UNITY_BUILDS BOOL OFF Enable unity builds (single TU compilation)
ASCIICHAT_ENABLE_ANALYZERS BOOL Auto Enable static analyzers (ON for Release, OFF otherwise)

Release Build Options

These options control Release build behavior:

Option Type Default Description
ASCIICHAT_ENFORCE_STATIC_RELEASE BOOL ON Enforce static linking for Release builds
ASCIICHAT_RELEASE_CPU_TUNE STRING portable CPU baseline (portable, x86-64-v2, x86-64-v3, native, custom)
ASCIICHAT_RELEASE_CPU_CUSTOM_FLAGS STRING "" Custom CPU flags when CPU_TUNE=custom
ASCIICHAT_RELEASE_ENABLE_FAST_MATH BOOL OFF Enable aggressive fast-math optimizations
ASCIICHAT_RELEASE_KEEP_FRAME_POINTERS BOOL ON Keep frame pointers for crash debugging

Packaging and Installation Options

Option Type Default Description
USE_CPACK BOOL ON Enable CPack package generation
ASCIICHAT_CODESIGNING BOOL Auto Enable macOS code signing (ON for Release on macOS)
CODESIGNING_IDENTITY STRING "" macOS code signing identity (from env or CMake)

Testing Options

Option Type Default Description
ASCIICHAT_ENABLE_CTEST_DASHBOARD BOOL OFF Enable CTest dashboard submission

Dependency Cache Options

Option Type Default Description
ASCIICHAT_DEPS_CACHE_ROOT PATH "${CMAKE_SOURCE_DIR}/.deps-cache" Root directory for dependency caches
ASCIICHAT_DEPS_CACHE_DIR PATH Auto Build-type specific cache directory

Cache Directory Structure:

  • Debug/Dev: ${ASCIICHAT_DEPS_CACHE_ROOT}/debug/
  • Release: ${ASCIICHAT_DEPS_CACHE_ROOT}/release/
  • musl: ${ASCIICHAT_DEPS_CACHE_ROOT}/musl/

Options Summary

Common Configurations:

# Debug build (default)
cmake -B build -DCMAKE_BUILD_TYPE=Debug
# Release build with defaults
cmake -B build -DCMAKE_BUILD_TYPE=Release
# Release with specific CPU tuning
cmake -B build -DCMAKE_BUILD_TYPE=Release \
-DASCIICHAT_RELEASE_CPU_TUNE=x86-64-v3
# Debug with panic instrumentation
cmake -B build -DCMAKE_BUILD_TYPE=Debug \
-DASCIICHAT_BUILD_WITH_PANIC=ON
# Disable tests for faster builds
cmake -B build -DBUILD_TESTS=OFF
# Custom dependency cache location
cmake -B build -DASCIICHAT_DEPS_CACHE_ROOT=/path/to/cache

Dependency Caches

Cache Overview

The build system uses multiple caching mechanisms to speed up builds and persist dependencies across build directory deletions:

Cache Types:

  • ccache: Compiler cache (speeds up recompilation)
  • FetchContent: Dependency caching (persists across builds)
  • CMake Cache: Configuration cache (persists in CMakeCache.txt)

Compiler Cache (ccache)

Purpose: Cache compilation results to speed up rebuilds

Automatic Detection:

  • ccache automatically detected if available
  • Enabled by default (USE_CCACHE=ON)
  • Disabled automatically for musl builds (incompatible)

Configuration:

  • Max Size: 2GB (configurable)
  • Compression: Enabled (level 6)
  • Cache Location: System default (usually ~/.ccache/)

Manual Configuration:

# Set cache size
ccache --set-config max_size=4G
# Show cache statistics
ccache --show-stats
# Clear cache
ccache --clear

Disabling ccache:

# Disable for specific build
cmake -B build -DUSE_CCACHE=OFF -DCMAKE_BUILD_TYPE=Debug
# Disable globally (environment variable)
export USE_CCACHE=OFF
cmake -B build -DCMAKE_BUILD_TYPE=Debug

Performance Impact:

  • First build: No benefit (cache population)
  • Subsequent builds: 5-10x faster compilation
  • Cache hit rate: Typically 70-90% for incremental builds

Dependency Cache (.deps-cache/)

Purpose: Cache built dependencies to survive build/ directory deletion

ascii-chat uses a centralized dependency cache system with build-type separation. This is controlled by ASCIICHAT_DEPS_CACHE_* CMake variables, which also configure FETCHCONTENT_BASE_DIR automatically.

Cache Structure:

.deps-cache/
β”œβ”€β”€ Debug/ # Debug build dependencies
β”‚ β”œβ”€β”€ mimalloc/ # mimalloc with debug checks
β”‚ β”œβ”€β”€ bearssl/ # BearSSL library
β”‚ β”œβ”€β”€ musl/ # (if USE_MUSL=ON)
β”‚ └── ... # Other FetchContent deps
β”œβ”€β”€ Release/ # Release build dependencies
β”‚ β”œβ”€β”€ mimalloc/ # mimalloc optimized
β”‚ β”œβ”€β”€ bearssl/ # BearSSL library
β”‚ β”œβ”€β”€ musl/ # (if USE_MUSL=ON)
β”‚ └── ...
└── Dev/ # Dev build dependencies
└── ...

CMake Variables:

Variable Description
ASCIICHAT_DEPS_CACHE_ROOT Root directory (default: .deps-cache/)
ASCIICHAT_DEPS_CACHE_DIR Build-type specific (e.g., .deps-cache/Debug/)
ASCIICHAT_DEPS_CACHE_MUSL Musl deps (e.g., .deps-cache/Release/musl/)

Custom Cache Location:

# Set custom cache root
cmake -B build -DCMAKE_BUILD_TYPE=Release \
-DASCIICHAT_DEPS_CACHE_ROOT="$HOME/.cache/ascii-chat-deps"

Cache Management:

# View cache size
du -sh .deps-cache
# Clear all cached dependencies (full rebuild)
rm -rf .deps-cache
# Clear only Debug dependencies
rm -rf .deps-cache/Debug
# Force dependency rebuild without clearing cache
rm -rf build && cmake -B build -DCMAKE_BUILD_TYPE=Debug

Benefits:

  • Dependencies survive rm -rf build (3-4x faster clean rebuilds)
  • Separate caches per build type (Debug vs Release optimizations)
  • Shared across multiple build directories
  • Docker builds use .deps-cache/<DOCKER_OS>/ for isolation

musl Dependency Cache

Purpose: Cache statically built dependencies for musl builds

Cache Location:

  • Default: .deps-cache/<BuildType>/musl/ (e.g., .deps-cache/Release/musl/)
  • CMake variable: ASCIICHAT_DEPS_CACHE_MUSL
  • Prefix: MUSL_PREFIX variable (set to cache location)

Cached Dependencies:

  • zstd: Static library built with musl toolchain
  • libsodium: Static library built with musl toolchain
  • PortAudio: Static library built with musl toolchain
  • BearSSL: Static library built with musl toolchain
  • Kernel Headers: Copied to $MUSL_PREFIX/kernel-headers/

Building Dependencies:

  • Dependencies built from source during first musl build
  • Build results cached in MUSL_PREFIX (same as ASCIICHAT_DEPS_CACHE_MUSL)
  • Subsequent musl builds reuse cached dependencies

Cache Structure:

.deps-cache/Release/musl/
β”œβ”€β”€ bin/ # Compiled tools (if any)
β”œβ”€β”€ include/ # Header files
β”œβ”€β”€ lib/ # Static libraries (.a files)
β”œβ”€β”€ kernel-headers/ # Linux kernel headers
β”‚ β”œβ”€β”€ linux/
β”‚ β”œβ”€β”€ asm/
β”‚ └── asm-generic/
└── share/ # Other files

Windows Build Script

Script Overview

The build.ps1 PowerShell script simplifies Windows builds by:

  • Automatically detecting and configuring the best compiler
  • Using CMake presets for common configurations
  • Handling MSVC library detection
  • Managing build directories
  • Copying outputs to bin/ directory
  • Killing conflicting processes before building

Script Location: build.ps1 in project root

Usage:

# Default Debug build
.\build.ps1
# Release build
.\build.ps1 -Config Release
# Dev build (no sanitizers)
.\build.ps1 -Config Dev
# Debug build with coverage
.\build.ps1 -Config Debug -CFlags "--coverage"
# Clean rebuild
.\build.ps1 -Clean
# Custom compiler flags (disables presets)
.\build.ps1 -CFlags "-DDEBUG_THREADS","-DDEBUG_MEMORY"
# Disable mimalloc
.\build.ps1 -NoMimalloc
# Use Visual Studio generator with Clang
.\build.ps1 -VSWithClang
# Custom build directory
.\build.ps1 -BuildDir mybuild

Key Features

Automatic Compiler Detection:

  • Prefers Clang (gcc untested and unsupported)
  • Respects CC environment variable

CMake Preset Integration:

  • Uses CMake presets when possible
  • Falls back to custom configuration when flags don't match presets
  • Automatic preset selection based on -Config parameter

Process Management:

  • Kills running ascii-chat processes before building
  • Prevents build failures from locked files
  • Waits for processes to terminate

Output Management:

  • Copies build outputs to bin/ directory
  • Creates bin/ directory if it doesn't exist
  • Preserves directory structure

Configuration Detection:

  • Only configures if build directory doesn't exist
  • Skips configuration on subsequent builds (faster)
  • -Clean flag forces reconfiguration

Installation and Packaging

Installation Overview

The Install.cmake module configures installation rules and CPack package generation for distributing ascii-chat across different platforms.

Installation Components:

  • Runtime: Binary executable (ascii-chat)
  • Documentation: README, LICENSE, CHANGELOG (if available)
  • Manpages: Unix manual pages generated by Doxygen (if built)

Platform-Specific Installation:

  • Linux: Follows FHS (Filesystem Hierarchy Standard)
  • macOS: Follows macOS conventions
  • Windows: Follows Windows conventions

Basic Installation

Standard Installation:

# Build the project first
cmake --build build
# Install to default location (/usr/local on Unix, Program Files on Windows)
cmake --install build
# Install to custom prefix
cmake --install build --prefix /custom/install/path

Component-Based Installation:

# Install only the binary
cmake --install build --component Runtime
# Install binary and documentation
cmake --install build --component Runtime --component Documentation
# Install everything (default)
cmake --install build

Manpage Installation

Manpages are automatically generated by Doxygen and installed if available:

Generating Manpages:

# Build documentation (generates manpages)
cmake --build build --target docs
# Install (manpages will be included automatically)
cmake --install build

Manpage Location:

  • Installed to: share/man/man3/
  • Format: ascii-chat-<function>.3
  • View with: man ascii-chat-<function>

CPack Package Generation

CPack is configured to generate platform-specific packages for distribution.

Supported Package Formats:

  • Linux: TGZ (always), DEB (if dpkg-buildpackage found), RPM (if rpmbuild found)
  • macOS: TGZ (always), PKG (if productbuild available)
  • Windows: ZIP (always), NSIS/EXE (if makensis found)

Generating Packages:

# Build the project first
cmake --build build
# Generate packages (all available formats for your platform)
cmake --build build --target package
# Packages are created in build/packages/
ls build/packages/

Disable CPack:

# Disable package generation
cmake -B build -DUSE_CPACK=OFF

Package Contents:

  • Binary executable (Runtime component)
  • Documentation files (README, LICENSE, CHANGELOG)
  • Manpages (if generated via docs target)

Platform-Specific Package Details:

Linux DEB Packages:

  • Architecture: Automatically detected (amd64, arm64)
  • Maintainer: From DEBEMAIL environment variable or default
  • Section: net
  • Dependencies: None (statically linked)

Linux RPM Packages:

  • Architecture: Automatically detected (x86_64, aarch64)
  • Vendor: From RPM_VENDOR environment variable or default
  • Group: Applications/Networking
  • License: MIT

macOS PKG Packages:

  • Format: Flat package installer
  • Installer ID: com.zfogg.ascii-chat
  • Installs to: /usr/local/bin/

Windows NSIS Installers:

  • Adds executable to PATH automatically
  • Uninstall support
  • Optional: Custom installer icon

Source Packages:

# Generate source distribution package
cmake --build build --target package_source

Source packages exclude:

  • Build directories (build/, build_release/)
  • Dependency caches (.deps-cache/)
  • Git directory (.git/)
  • IDE files (.vscode/, .idea/)
  • Build artifacts (.ninja_log, compile_commands.json)

Installation Configuration

Installation Paths:

  • Binary: bin/ (relative to install prefix)
  • Documentation: share/doc/ascii-chat/
  • Manpages: share/man/man3/

Custom Installation Prefix:

# Install to custom location
cmake --install build --prefix /opt/ascii-chat
# Verify installation
ls /opt/ascii-chat/bin/ascii-chat
ls /opt/ascii-chat/share/doc/ascii-chat/
ls /opt/ascii-chat/share/man/man3/

Installation Components:

  • Runtime: Required component (binary)
  • Documentation: Optional (README, LICENSE, CHANGELOG)
  • Manpages: Optional (requires docs target to be built)
See also
cmake/Install.cmake
CMakeLists.txt
cmake/
CMakePresets.json
build.ps1
release.sh