|
ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
|
π¨ Compile human-readable code into machine-executable code
π¨ Compile human-readable code into machine-executable code
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:
Build and install ascii-chat:
Or use CMake directly with presets:
Or configure manually:
See CMake Presets (Preferred) for all available presets and CMake Configuration Options for configuration options.
ascii-chat has a few goals to satisfy, and the build system reflects them all.
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:
Build modes:
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 librarylibasciichat.a / asciichat.lib - Static libraryWe 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 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?
Platform linking:
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.
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/.
| 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 |
This section documents tools needed to build ascii-chat. For library dependencies (zstd, libsodium, PortAudio, etc.), see Dependencies README.
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) |
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 |
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:
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 |
Quick check that all required tools are available:
If any tool is missing, the CMake configure step will fail with a clear error message explaining what to install.
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:
The main CMakeLists.txt is organized as a modular system, with each major aspect handled by a dedicated module in the cmake/ directory:
Root-level Modules:
ProjectConstants.cmake - Project metadata (name, author, URLs, license)Core Configuration Modules (init/):
init/Init.cmake - Initial setup and pathsinit/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 helpersinit/PlatformDetection.cmake - Platform-specific variables (Linux, macOS, Windows)Compiler Configuration (compiler/):
compiler/CompilerDetection.cmake - Compiler detection and configurationcompiler/CompilerFlags.cmake - Base compiler flags and standardscompiler/CCache.cmake - Compiler cache configurationcompiler/SIMD.cmake - SIMD instruction detectioncompiler/CRC32.cmake - Hardware-accelerated CRC32 detectioncompiler/PCH.cmake - Precompiled headerscompiler/LLVM.cmake - LLVM toolchain configurationcompiler/HeaderChecks.cmake - Header availability checkscompiler/ToolchainChecks.cmake - Toolchain validationPlatform Configuration (platform/):
platform/WindowsWorkarounds.cmake - Windows-specific fixesplatform/CodeSigning.cmake - macOS code signing for Gatekeeper compatibilityplatform/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 integrationdependencies/BearSSL.cmake - BearSSL TLS librarydependencies/Criterion.cmake - Criterion test frameworkdependencies/Libsodium.cmake - libsodium cryptography librarydependencies/Mimalloc.cmake - mimalloc memory allocatordependencies/MuslDependencies.cmake - Static dependency building for musldependencies/Portaudio.cmake - PortAudio audio librarydependencies/Zstd.cmake - Zstandard compression libraryBuild Targets (targets/):
targets/SourceFiles.cmake - Source file collectiontargets/Libraries.cmake - Library linkingtargets/Executables.cmake - Executable targetstargets/Tests.cmake - Test framework configurationInstallation and Packaging (install/):
install/Install.cmake - Installation rules and CPack package generationinstall/Archive.cmake - Archive package configuration (ZIP, TGZ)install/Deb.cmake - Debian package configurationinstall/Rpm.cmake - RPM package configurationinstall/Version.cmake - Version generationinstall/Documentation.cmake - Doxygen documentationTesting (test/):
test/TestFramework.cmake - Test framework setupTooling 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 configurationutils/PostBuild.cmake - Post-build processingutils/StatusMessages.cmake - Build status outputtargets/CustomTargets.cmake - Custom build targets (format, clang-tidy, etc.)CMake Presets are the preferred way to configure builds. They provide standardized configurations with all the right flags for each build type.
| 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 |
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.
Create custom presets by editing CMakePresets.json:
Purpose: Finding bugs, memory issues, undefined behavior
Configuration:
Features:
-O0 (no optimization)When to Use:
Purpose: Fast compilation, daily development
Configuration:
Features:
-O0 (no optimization)When to Use:
Purpose: Production deployment, performance testing
Configuration:
Features:
-O3 (maximum optimization)Stack Protection: -fstack-protector-strong kept enabled on Unix
-Wl,-pie, Windows /dynamicbase + /highentropyva)/guard:cf and /nxcompat enforced when using clang-cl-Wl,-dead_strip_dylibs removes unused framework depsSecurity & Portability Philosophy:
-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.Configurable Release Knobs:
-DASCIICHAT_RELEASE_CPU_TUNE=portable|x86-64-v2|x86-64-v3|native|customportable (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 ..."ASCIICHAT_RELEASE_CPU_TUNE=custom.-DASCIICHAT_RELEASE_ENABLE_FAST_MATH=ONOFF to keep IEEE semantics for audio mixing and crypto code; toggle only after profiling the hot loops you own.-DASCIICHAT_RELEASE_KEEP_FRAME_POINTERS=OFFON keeps frame pointers so postmortem tooling (Crashpad, addr2line, symbolicators) can reconstruct stacks from field crashes.-DASCIICHAT_CODESIGNING=ON|OFF (macOS only)ON in Release mode, OFF in all other build types.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:
Purpose: Optimized build with debug symbols for debugging production issues
Configuration:
Features:
-O3 (maximum optimization)When to Use:
Debug Symbols in Production:
strip build/bin/ascii-chat.debug file)Windows PDB Files:
build/bin/ directoryPurpose: 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:
Features:
--coverage -fprofile-arcs -ftest-coverageGenerating Coverage Reports:
When to Use:
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.
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 |
| Option | Type | Default | Description |
|---|---|---|---|
USE_MIMALLOC | BOOL | Auto | Enable mimalloc allocator (ON for Release/RelWithDebInfo, OFF otherwise) |
| Option | Type | Default | Description |
|---|---|---|---|
USE_MUSL | BOOL | Auto | Use musl libc for static linking (ON for Release/RelWithDebInfo on Linux) |
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 enables per-statement logging for debugging crashes. When the program crashes, the last line printed is the crashing line.
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:
defer statements in C codedefer() - no option neededbuild/defer_transformed/Usage Example:
| 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) |
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 |
| 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) |
| Option | Type | Default | Description |
|---|---|---|---|
ASCIICHAT_ENABLE_CTEST_DASHBOARD | BOOL | OFF | Enable CTest dashboard submission |
| 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:
${ASCIICHAT_DEPS_CACHE_ROOT}/debug/${ASCIICHAT_DEPS_CACHE_ROOT}/release/${ASCIICHAT_DEPS_CACHE_ROOT}/musl/Common Configurations:
The build system uses multiple caching mechanisms to speed up builds and persist dependencies across build directory deletions:
Cache Types:
CMakeCache.txt)Purpose: Cache compilation results to speed up rebuilds
Automatic Detection:
USE_CCACHE=ON)Configuration:
~/.ccache/)Manual Configuration:
Disabling ccache:
Performance Impact:
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:
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:
Cache Management:
Benefits:
rm -rf build (3-4x faster clean rebuilds).deps-cache/<DOCKER_OS>/ for isolationPurpose: Cache statically built dependencies for musl builds
Cache Location:
.deps-cache/<BuildType>/musl/ (e.g., .deps-cache/Release/musl/)ASCIICHAT_DEPS_CACHE_MUSLMUSL_PREFIX variable (set to cache location)Cached Dependencies:
$MUSL_PREFIX/kernel-headers/Building Dependencies:
MUSL_PREFIX (same as ASCIICHAT_DEPS_CACHE_MUSL)Cache Structure:
The build.ps1 PowerShell script simplifies Windows builds by:
bin/ directoryScript Location: build.ps1 in project root
Usage:
Automatic Compiler Detection:
CC environment variableCMake Preset Integration:
-Config parameterProcess Management:
Output Management:
bin/ directorybin/ directory if it doesn't existConfiguration Detection:
-Clean flag forces reconfigurationThe Install.cmake module configures installation rules and CPack package generation for distributing ascii-chat across different platforms.
Installation Components:
ascii-chat)Platform-Specific Installation:
Standard Installation:
Component-Based Installation:
Manpages are automatically generated by Doxygen and installed if available:
Generating Manpages:
Manpage Location:
share/man/man3/ascii-chat-<function>.3man ascii-chat-<function>CPack is configured to generate platform-specific packages for distribution.
Supported Package Formats:
dpkg-buildpackage found), RPM (if rpmbuild found)productbuild available)makensis found)Generating Packages:
Disable CPack:
Package Contents:
docs target)Platform-Specific Package Details:
Linux DEB Packages:
DEBEMAIL environment variable or defaultnetLinux RPM Packages:
RPM_VENDOR environment variable or defaultApplications/NetworkingmacOS PKG Packages:
com.zfogg.ascii-chat/usr/local/bin/Windows NSIS Installers:
Source Packages:
Source packages exclude:
build/, build_release/).deps-cache/).git/).vscode/, .idea/).ninja_log, compile_commands.json)Installation Paths:
bin/ (relative to install prefix)share/doc/ascii-chat/share/man/man3/Custom Installation Prefix:
Installation Components:
docs target to be built)