Minimalist C Architecture

c-programmingsoftware-architectureperformancesystems-design

In an era of increasing software bloat, the C ecosystem has become reliant on heavy build systems and deep dependency trees. This creates 'dependency hell,' slows developer feedback loops, and produces binaries with unnecessary overhead. This project explores a return to fundamental patterns.

Adopt a 'Header-less' Unity Build architectural pattern: eliminate external library dependencies and separate compilation in favor of X-Macros and single-translation-unit builds.

Standard Modular Compilation (CMake/Meson)

Pros
  • Widespread industry familiarity
  • Incremental builds save time in massive codebases
  • Clear interface separation via headers
Cons
  • Significant build-system maintenance overhead
  • Fragile dependency management
  • Inhibits global compiler optimizations (LTO required)

Dynamic Library Micro-services

Pros
  • Independent updates for system components
  • Shared memory across different applications
Cons
  • Runtime linking overhead
  • Version mismatch issues ('DLL Hell')
  • Increases attack surface for security vulnerabilities

A minimalist architecture reduces the 'cognitive load' of a project. By using X-Macros for state management and Unity Builds for compilation, the entire program logic becomes visible to the compiler at once. This enables aggressive optimization, near-instant build times, and produces tiny, zero-dependency binaries that run on any POSIX system.

The Bloat Problem

Modern systems development often prioritizes developer convenience over machine efficiency. This leads to:

  • Binary Bloat: Simple utilities often exceed several megabytes due to static linking of unused library code.
  • Slow Feedback: Complex build systems can take seconds or minutes to resolve dependencies before a single line is compiled.
  • Fragmentation: Memory management becomes inconsistent when mixing multiple third-party allocation strategies.

Architectural Pillars

We codified three pillars to maintain a professional, scalable codebase without the traditional baggage:

1. The TBL (Table) Macro Pattern

We replaced complex config parsers and global registry arrays with X-Macros. This allows a single definition of a system component—like a keybinding or an error code—to be expanded multiple times for different purposes (e.g., generating an enum, a string array for logging, and a dispatch table).

2. Unity Builds (Single Translation Unit)

Instead of compiling ten .c files into ten .o files and linking them, we include all implementation files into a single main.c.

  • Near-Instant Builds: Compiling with tcc (Tiny C Compiler) takes less than 50ms.
  • Global Optimization: The compiler performs constant folding and dead-code elimination across the entire project without needing a separate Link-Time Optimization (LTO) pass.

3. Custom Memory Arenas

To bypass the fragmentation of malloc, we use linear memory arenas. This allows for deterministic allocation and “frame-based” deallocation, which is significantly faster and easier to debug than tracking individual pointers.

Results & Impact

  • Compilation Speed: Build times dropped from ~2 seconds (Make/GCC) to < 50ms (TCC), enabling a ‘save-to-test’ loop that feels instantaneous.
  • Binary Footprint: Core system utilities (like FocusWM) were reduced to under 50KB, fitting entirely within the CPU’s L1 cache for maximum execution speed.
  • Portability: Binaries are statically linked against a minimal libc, allowing them to run on any Linux kernel version without requiring specific shared libraries.
  • Maintainability: The entire architecture is contained within a few hundred lines of code, making it possible for a single developer to hold the entire system state in their head.

The Road Ahead

The primary challenge remains standardization. While this architecture is perfect for solo power-users and high-performance system tools, it requires a shift in mindset for collaborative environments. My next goal is to document a “Minimalist C Standard Library” to provide a common ground for developers adopting this pattern.