Build Systems with Andrey Mokhov
Core Definition and Evolution
- Build systems automate tedious, ordered developer tasks including compilation, testing, and documentation updates.
- Prior to 1976, developers relied on manual scripts to manage build tasks.
- The introduction of
Makewas a breakthrough due to its simple, text-based rule format defining inputs, outputs, and commands. Makeremains the most popular build system globally, found in the majority of open-source projects.
Key Services Provided by
Make- Incrementality: Re-runs only tasks whose inputs have changed (based on timestamps), avoiding full rebuilds.
- Correctness: Ensures tasks execute in the correct dependency order, preventing errors from skipped steps.
- Parallelism: Enables concurrent execution of independent tasks, a feat difficult to manage manually.
Limitations of
Make- Overly Conservative Timestamp Heuristic: Recomputes downstream tasks even if the source file change (e.g., a comment) does not alter the output, wasting compute resources.
- Under-Conservative Timing: Fails to rebuild when external factors (e.g., backup software) alter file modification times incorrectly.
- Lack of Scalability: Cannot share build artifacts across different machines; every developer builds from scratch.
- Poor Composability: Uses a single global namespace with mutable variables, making it difficult to reason about build rules locally.
- Macros and Generativity: Complex logic requires string-splicing macros, which are hard to debug and often generate more macros (meta-programming), leading to "impenetrable" build files.
- Static Rule Requirement: Requires all build tasks to be defined upfront; cannot easily handle scenarios where new rules are generated dynamically during the build process.
Case Study: GHC and Hadrian
- The Glasgow Haskell Compiler (GHC) contains approximately 1 million lines of code and relied on a fragmented system of 20–30 large
Makefiles. - Migration to Hadrian, a new build system for GHC, evolved from a 90% code rewrite into an "archaeology expedition" to extract 25 years of undocumented build knowledge.
- Hadrian is functional and in use, but the migration remains ongoing due to the complexity of preserving legacy, conditional logic.
- The Glasgow Haskell Compiler (GHC) contains approximately 1 million lines of code and relied on a fragmented system of 20–30 large
Theoretical Framework: "Build Systems a la Carte"
- Core Abstraction: All build systems can be modeled as a combination of two components: a Scheduler (determines execution order) and a Rebuilder (handles task execution, caching, and cloud interaction).
- Taxonomy: The analysis identified four distinct schedulers and three distinct rebuilder strategies, allowing for 12+ combinations, some of which were previously unknown.
- Innovation Example: The paper proposed Cloud Shake, combining the Shake scheduler with Bazel's "constructive traces" rebuilder.
- Uses a "suspending scheduler" to handle dynamic dependencies.
- Uses task hashes to query cloud storage for pre-computed results, avoiding redundant local computation.
Fragmentation and the Language Problem
- The ecosystem is fractured because build rules are typically written in the language of the target community (e.g., Java for Bazel, OCaml for Dune, Haskell for Shake).
- While this allows for better tooling integration and community iteration, it prevents cross-language monorepos (e.g., mixing Rust, Haskell, and Java) without complex glue code.
- Generative Build Systems: A proposed but unrealized architecture involves a language-agnostic engine that accepts initial rules, iterates with the user, and generates new rules based on feedback until a fixed point is reached.
Jane Street's Build Systems: Jenga and Dune
- Jenga:
- Designed specifically for Jane Street's 15–20 million line monorepo.
- Uses a two-tier language model: a constrained, data-oriented frontend for developers and a full OCaml backend for execution.
- Currently lacks native cloud build support; the build team is working to add this feature.
- Dune:
- An OCaml build system used by the broader OCaml community.
- Features a versioned build language, allowing independent projects to evolve their build rules without breaking compatibility.
- Initially faster than Jenga for "from scratch" builds; now incorporates incrementality and rudimentary cloud features.
- Migration Strategy: Jane Street plans to migrate from Jenga to Dune but faces the "dual-work" challenge of maintaining features in both systems until Dune matches Jenga's scale.
- Future Architecture: Plans to decouple Dune into a backend (incremental engine) and frontend (rule definitions) to allow Jenga to adopt the Dune frontend while retaining its current backend.
- Jenga:
Integration and Granularity Trends
- IDE Integration: Modern build systems are integrating directly with editors to enable "continuous compilation" and instant error reporting, reducing iteration cycles to milliseconds.
- Compiler Coupling: Building systems are beginning to automate compiler tasks (type checking, analysis) rather than just file compilation.
- Fine-Grained Incrementality: Systems like Facebook's "Hack" demonstrate millisecond updates by tracking dependencies at the function level, requiring persistent, stateful servers to avoid serialization overhead.
- Technical Barrier: As granularity decreases (line-level vs. file-level), the cost of serializing state may outweigh the benefits of computation, necessitating persistent build servers or shared memory models.
Broader Scope: Incremental Computation
- Excel Analogy: Spreadsheets function as incremental computation engines for non-file data, using fixed-point iteration to resolve circular dependencies.
- Scientific Workflows: Scientific computing pipelines (e.g., bioinformatics) share build system goals (caching, parallelism) but differ by requiring distributed orchestration across massive datasets and long-running jobs (weeks/months).
- Convergence: Modern build systems and incremental data structures (e.g., incremental maps, sorting) are converging as systems move toward persistent, stateful execution environments.