Jamfile
The build-specification file and interpreted language of Jam, Christopher Seiwald's portable make replacement that tracks dependencies automatically and builds large multi-directory projects in a single pass.
Created by Christopher Seiwald (Perforce Software)
A Jamfile is the build-specification file used by Jam, an open-source software construction tool created by Christopher Seiwald of Perforce Software as a replacement for the venerable Unix make. Where make reads a Makefile, Jam reads one or more Jamfiles written in Jam’s own small, interpreted language. The defining promise is simple: instead of laboriously spelling out which files depend on which — and writing the shell commands to rebuild each one — the author of a Jamfile mostly just lists the source files, and Jam figures out the dependency graph, including header dependencies, automatically and on the fly.
History & Origins
Seiwald released Jam 1.0 in November 1993, and the tool’s documentation carries a Copyright 1993–2002 Christopher Seiwald and Perforce Software notice. It was born from the same frustrations that have spawned countless make alternatives: makefiles are verbose, their recursive-make idioms are error-prone, and managing header dependencies by hand is tedious and fragile. Jam’s answer was to combine a built-in rule library (the Jambase) with a compact per-project description (the Jamfile), and to let the engine track relationships among files across an entire source tree in a single pass.
The original Perforce releases marched forward steadily — 2.0 (March 1994), 2.1 (February 1996), 2.2 (October 1997), 2.3 (November 2000), 2.4 (March 2002), and 2.5 (December 2002). After a long gap, Perforce published a final release, Jam 2.6, in August 2014, and indicated it would be the last official version. By then the most active development had long since moved to forks.
How a Jamfile Works
Jam separates “how to build things in general” from “what this particular project contains”:
- Jambase — a default file, written in Jam’s interpreted language, that ships with the tool. It defines the boilerplate rules (such as how to compile a C file or link an executable) and the variable assignments common to most builds. Users can replace or extend it with the
-fflag. - Jamfile — the user-supplied file, pulled in by the Jambase via an
includerule. It enumerates the actual targets and their sources and how they relate.
A characteristic Jamfile is strikingly short. Rather than listing object files, link commands, and header dependencies, the author invokes high-level rules:
# Build a library and a program that uses it
Library libhello : hello.c greeting.c ;
Main hello : main.c ;
LinkLibraries hello : libhello ;
From this, Jam derives the object files, discovers #included headers automatically, sequences the compile and link steps, and rebuilds only what is out of date. Because dependencies are computed from the whole tree at once, Jam does not need the recursive make invocations that classic Unix builds rely on.
The Jam Language
Jamfiles and the Jambase are written in the same language — a small interpreted language with a deliberately spare model:
- Everything is a list of strings. Variables hold whitespace-separated lists; there are no numeric or structured types in the traditional sense. This makes the language easy to learn but unusual to read at first.
- Rules are the language’s procedures. They can both compute values and declare dependencies between targets.
- Actions attach the shell commands that actually update a target, separated from the dependency logic that decides whether to run them.
- Built-in variables and modifiers let Jamfiles adapt commands per-platform and per-target.
This expressiveness is what keeps Jamfiles compact: build logic that would sprawl across a Makefile can be captured in a few rule invocations, with the messy details living once in the shared Jambase.
Key Features
- Automatic header-dependency scanning. Jam parses source files to find included headers and folds them into the dependency graph without the author maintaining a separate dependency list.
- Single-pass, tree-wide builds. Jam tracks relationships among all files across many directories at once, avoiding recursive-make pitfalls.
- Parallel builds. Jam can run multiple update actions concurrently, an early and practical answer to build-time pressure.
- Portability. Per its documentation, Jam ran on Unix variants, OpenVMS, Windows NT, classic Mac OS, and BeOS (with Windows 9x reachable via MinGW or Cygwin). (Platform support reflects the tool’s historical documentation rather than current testing.)
The Jambase has, fairly or not, a reputation among long-time users for harboring quirks and bugs that were infrequently fixed — a side effect of so much default behavior living in one shared, evolving file.
Evolution and Forks
Jam’s lasting influence flows mostly through its descendants, which kept the Jamfile model alive as the original tool slowed:
- FT-Jam — a backward-compatible fork maintained by the FreeType project.
- Boost.Jam / b2 — the build engine of Boost.Build, derived from FT-Jam (and thus from Perforce Jam). Boost.Build is itself written in the Jam language. In Boost 1.47.0 (2011) the executable was renamed from
bjamtob2, withbjamkept as a compatibility alias; b2 has since grown well beyond the original and is developed independently. - Haiku Jam — a custom fork used to build the Haiku operating system.
- JamPlus — a community-extended variant aimed at fast code-and-data builds, popular in game development.
These variants are not all mutually compatible — Boost.Jam in particular diverged enough that its Jamfiles are not portable to plain Jam — but they share the core idea that a build is described by concise, rule-driven Jamfiles rather than hand-managed dependency lists.
Current Relevance
The original Perforce Jam is, in practical terms, a finished project: its last official release was 2.6 in 2014. Yet the Jamfile lives on. The most visible heir is Boost.Build (b2), still maintained and used to build the Boost C++ Libraries, and the Haiku project continues to build an entire operating system with its own Jam fork. For developers who encounter a Jamfile (or Jamroot, Jamfile.v2, or a *.jam file) in a codebase today, it is almost always one of these descendants rather than Seiwald’s original tool.
Why It Matters
Jam is an important entry in the long lineage of “better make” tools. Its central insight — that programmers should declare what their project contains and let the build engine derive the how, including header dependencies, ordering, and parallelism — anticipated ideas that later build systems (CMake, Meson, Bazel, Ninja) would pursue in their own ways. The Jamfile demonstrated that a build description could be short, readable, and portable across wildly different operating systems, and its language proved expressive enough that an entire build framework (Boost.Build) could be written in it. For students of build tooling, the Jamfile is a compact case study in separating policy (the Jambase) from project specifics (the Jamfile), and a reminder that a well-designed small language can outlive the tool that introduced it.
Timeline
Notable Uses & Legacy
Boost C++ Libraries
Boost's build system, Boost.Build, is implemented in the Jam language and historically driven by Boost.Jam (bjam, later renamed b2), a Jam variant derived from FT-Jam and ultimately from Perforce Jam.
Haiku operating system
The Haiku project builds its entire BeOS-compatible operating system using a custom fork of Jam, with the build described in Jamfiles throughout the source tree.
FreeType (FT-Jam)
The FreeType font-rendering project maintained FT-Jam, a backward-compatible fork of Perforce Jam, and used Jamfiles to build the library across platforms.
Perforce
Perforce Software, where Jam originated, used it internally as a portable, high-performance build tool for cross-platform C and C++ development.
JamPlus
JamPlus is a community-driven, feature-extended Jam derivative used to build code and data for games and other projects, retaining the Jamfile model.