Haiku's Jam Build System: Cross-Tools, Hybrid ABIs, Packages, and Images
How Haiku's configure-and-Jam system coordinates host tools, target compilers, resources, packages, bootloaders, and complete images.
Building Haiku is not equivalent to compiling one C++ program. The repository must produce tools that run on the host, binaries that run on the target, resources and filesystem attributes associated with BeOS-style executables, boot components for different firmware environments, packages, and complete disk images. Haiku combines a relatively small configure script with its own extended variant of Jam to represent those relationships.
This separation is useful to remember when a command succeeds. Compiling an executable proves that target’s dependencies and actions completed. It does not necessarily prove that its package was rebuilt, that the package was selected for an image, or that a bootable image now contains the changed file. Jam can express all of those stages, but the developer must request the target that corresponds to the intended artifact.
Why Haiku uses its own Jam
Haiku’s internals documentation describes requirements that fall between a low-level dependency executor and a conventional high-level application build generator. The system needs reusable rules for common target types, but it also needs exact control over which compiler and flags apply to each target, how resources are added, how host utilities are built, and how non-code tasks fit into the dependency graph.
Jam expresses that model through rules, targets, variables, dependencies, and actions. A high-level rule such as Application can receive source files, libraries, and a resource definition. It delegates to lower-level rules that compile, link, and add resources. Eventually an action invokes an external command. Target-specific variables let the same general rules select different compilers or flags for different outputs.
Haiku’s rules live under build/jam in the source tree. The official build-system overview identifies files for major concerns: MainBuildRules covers Haiku and build-platform targets, ArchitectureRules handles architecture flags and hybrid builds, BootRules covers bootloaders, and KernelRules covers the kernel and kernel add-ons. BeOSRules addresses BeOS-like features such as executable resources and extended attributes.
This organization makes a Jamfile concise without making the underlying build simplistic. A target can depend on generated headers, libraries, resources, packages, and image assembly while sharing the implementation of those operations with hundreds of other targets.
Configure creates a build context
The repository’s configure script prepares the build context before Jam evaluates the full graph. Official build guides recommend a generated directory separate from the source tree. Architecture-specific instructions run configure from that directory with options pointing back to buildtools and selecting the target architecture or a prebuilt cross-tools prefix.
An out-of-tree directory has operational benefits. Generated headers, object files, downloaded packages, emulated attributes, and final images remain separate from version-controlled sources. Multiple generated directories can represent different architectures or configurations without repeatedly rewriting one output tree. The exact configure invocation should be recorded with bug reports because compiler selection and build options can change the meaning of later Jam results.
Cross-building divides software into host and target domains. A resource compiler or package-building utility used during the build must execute on the host. The kernel, libraries, and applications it produces must use the target ABI. Confusing those domains can yield an executable that compiled successfully but cannot run at the stage where the build needs it.
Hybrid builds can involve three compilers
Haiku’s Jam documentation notes that a build may involve as many as three compilers: one for the host and, for a hybrid configuration, two target compilers. The historically important x86 hybrid combines compatibility with GCC 2-era BeOS binaries and components built with a newer GCC ABI. The build system must know which side of that boundary owns each target and link it only against compatible objects and libraries.
This is more than selecting an optimization flag. C++ name mangling, standard library ABI, exception machinery, and binary interfaces can differ. A library built for one ABI is not automatically interchangeable with a library of the same name built for the other. Architecture and hybrid rules attach the correct compiler and search paths to each target so a high-level package or image can contain the necessary variants without accidentally linking them together.
The host compiler is a third independent concern. It builds utilities for the developer’s current operating system, possibly using compatibility support for Haiku-specific concepts. A successful host tool does not demonstrate the target compiler, and a successful target library does not demonstrate that an image-generation utility can execute on the host.
Resources and attributes are first-class build outputs
Haiku applications can carry resources, and BFS supports extended attributes used throughout the system’s metadata model. Many host filesystems do not provide identical semantics. The official Jam guide says the build system emulates attributes when the build filesystem is not BFS and lacks a sufficient xattr implementation. An attributes/ directory under the generated output can hold that emulated state.
The existence of emulation explains two otherwise surprising behaviors. First, copying only an ordinary file may not preserve all build metadata. Second, stale emulated attributes can survive separately from a rebuilt object. The guide documents cleaning the generated attribute store when troubleshooting that condition, after running the appropriate clean operation.
Resources are also a separate action in the dependency chain. The simplified Application example in Haiku’s Jam documentation invokes both the main compilation/link rules and AddResources. A source rebuild and a resource update are related, but not conceptually identical. Correct dependencies ensure the final executable is refreshed when either input changes.
Packages and images add additional layers
Haiku’s package-management infrastructure builds core system packages from the Haiku tree and incorporates packages from configured repositories into images. A target binary may first be staged into an HPKG; the image target then selects packages and lays out boot-related artifacts. Rebuilding one layer does not imply that every downstream layer was requested or updated.
This is the source of a common false positive: a developer inspects a freshly linked binary in the object tree, boots an older image, and concludes that the code change had no effect. The right verification follows the artifact chain. Identify which package owns the file, confirm that package’s timestamp or contents changed, rebuild the intended image target, and inspect or boot the newly generated image rather than a similarly named older output.
Different image profiles intentionally contain different software. Minimal targets are useful for bringing up a port or debugging foundational services; release-oriented targets select a broader defined system. A Jam target name is therefore part of the test evidence. “The build passed” is incomplete without the configured architecture and the exact requested target.
Jam options that change diagnosis
Haiku’s official Jam guide recommends -q so Jam stops at the first encountered error instead of continuing independent targets and burying the originating failure. -j selects parallelism, which reduces build time but can interleave diagnostics. The -n option performs a dry run, showing what would be updated without executing the actions, and debug modes can expose commands, causes, or dependency information.
The -a option forces targets to rebuild even when Jam considers them current. The guide warns that this may be needed after certain Jamfile or dependency changes, but it should be treated as a diagnostic or recovery tool rather than the default response to every failure. A forced rebuild can hide an incorrect dependency edge that ought to be fixed.
Variables can be overridden with -sNAME=value; Haiku’s documented example uses HAIKU_IGNORE_USER_BUILD_CONFIG when an exact default profile is required. UserBuildConfig and build profiles are powerful because they allow local customization, but those local settings must be disclosed when reproducing an official-image or another developer’s result.
A reproducible workflow
Keep source, buildtools, and generated output in a documented layout. Save the source revision, buildtools revision, host operating system, configure command, Jam version, and requested target. Run Jam as the normal user; Haiku’s guide explicitly warns against running the build with sudo, because root-owned generated files and an incorrectly selected disk target can turn an ordinary mistake into damage.
When a change seems absent, do not immediately erase the entire tree. Use Jam’s explanations or dry run to determine whether the relevant target is considered current. Check whether the source feeds the expected object, whether the object feeds the expected binary, whether resources were reapplied, whether the package was rebuilt, and whether the image includes that package. Clean or force only the narrow layer whose dependency state is suspect, then retain the evidence needed to repair the build rule if the problem recurs.
Finally, validate the artifact at the same level as the claim. A compiler change needs relevant target binaries or tests. A package recipe change needs package-content inspection. A bootloader change needs the correct firmware path. An image-profile change needs the generated package list and a boot test. Jam’s strength is that all these products can inhabit one dependency model; reliable reporting still requires naming which product was actually built and verified.
Related:
- How to Cross-Compile Haiku from a Linux Host
- How to Set Up a Haiku Development Environment and Build From Source
Sources: