Core reference
The target types, configuration properties, and flags that ship in fabr’s core (STD.fabr) and are
always available, independent of any language plugin. Ecosystem-specific definitions (like
js_package) come from plugins — see the JavaScript reference.
This page is generated from fabr list-all, so it never drifts from the code.
Configuration
Section titled “Configuration”BUILD_OPERATION
Section titled “BUILD_OPERATION”Default: build
The current operation. Standard values are
- build = standard compile/link/package
- files = return the raw contents of the built target
- run = create a direct executable
- test = execute tests
BUILD_TYPE
Section titled “BUILD_TYPE”Default: debug
Build type: standard values are one of
- debug = no optimization, full debugging info (default)
- relwithdebinfo = full optimization but still debuggable
- release = full optimization, all debug info stripped
TARGET
Section titled “TARGET”Default: ${HOST}
The platform we are building for, as a clang/LLVM triple (e.g. arm64-apple-macosx15.0, x86_64-linux-gnu). Defaults to HOST — the machine fabr is running on — and is what dependency/native selection gates on; override it (-D TARGET=… or ref<TARGET=…>) to cross-compile.
TEST_EXPECTATIONS
Section titled “TEST_EXPECTATIONS”Default: check
What a test run does when its actual output diverges from an expectation it has on record (a snapshot entry, a golden expected-file):
- check = fail, reporting the difference (default)
- update = rewrite the record, and offer the new content back to the source
tree.
fabr test -uis sugar for setting this. Updates are offered, never applied by the build: an action is hermetic and cannot write to your tree, so the driver applies them, only on request, only after an otherwise-green run.
Targets
Section titled “Targets”catalog
Section titled “catalog”targetdef catalog { deps = FILES;}A catalog pins a fixed set of external requirements in one place. Its deps
are resolved jointly and once (a single version selection over the whole set),
and each resolved package is exposed by its package name: reference it as
<catalog>:<package> wherever a dependency is wanted, with the version fixed
here rather than repeated at each use. Because the whole set resolves together,
every consumer sees one consistent version of everything the catalog covers,
and does no resolution of its own.
generate
Section titled “generate”Operations: build
targetdef generate { srcs = FILES; run = REQUIRED COMMAND; output = STRING;}Run a command pipeline and collect its output — the codegen/genrule builder (a
build step, distinct from the interactive fabr run verb). run is a command
line: cmd args... [redirs] | cmd args... [redirs]. Each command is a fabr
runnable (a target/tool, mounted in its own sandbox dir); args are literal or a
glob expanded over srcs. | pipes stdout to the next stage’s stdin; > name
/ 2> name / &> name capture stdout / stderr / both as content named name;
< source streams a single-file reference to the first stage’s stdin. srcs
are input files staged at the sandbox root; output (a dir:glob) collects
files the tools wrote, unioned with the redirect captures (omit it for a pure
redirect genrule). Example:
generate docs { run = list_targetdefs --json | gendoc > reference.md; }script
Section titled “script”Operations: run
targetdef script { deps = FILES; entry = REQUIRED FILES; args = STRING;}Define a runnable plain shell script (run it with fabr run, collect its
output with the generic generate target, or check it with a golden test).
entry is the script FILE itself — it contributes the file to the install (at
its resolved name) and launches it with the shell; deps stage any further
support files (their filesets union flat — just files, no package mounting);
args are fixed leading arguments. It yields a runnable, it does not itself
execute.
Operations: run
targetdef serve { tool = REQUIRED FILES; deps = FILES; args = STRING; files = FILES;}Define a served program: a long-lived server plus the content it serves.
tool names the server — any runnable (a script/js_script target, or an
external package run via its bin); deps union additional support files
into the install; files are the served content, staged at the install
root; args are fixed leading arguments. The program launches with its
working directory at the staged install (its content is its world — unlike
a plain script under fabr run, which runs in the caller’s directory), so
e.g. a stock static server serves files with no path argument. Under
fabr run -w, a change to files is synced into the running server’s
staging area in place; only a change to the program itself (tool, deps,
args) restarts it. It yields a runnable, it does not itself execute.
Operations: build
targetdef sync { * = FILES;}A sync publishes built content to one or more destination coordinates. Its body
is a set of members written as <destination>:<address> = content (the
coordinate is the key, the identityless built content the value); the address’s
shape is the destination’s — an npm registry’s is <name>:<version>, e.g.
sync release { @npm:@fabr/core:0.1.0 = core; @npm:@fabr/cli:0.1.0 = cli; }Each destination packages its members jointly with the whole release as context
(npm rewrites a member’s manifest dependency on another member to that member’s
assigned version). Building the sync target produces the wire artifacts (a
dry-run); fabr sync uploads them, deps-first. The members are reference-keyed
bindings rather than fixed schema properties; * = FILES types them — any
coordinate key maps to a FILES (content) value.
targetdef fetch { * = STRING;}A fetch repository is a declared table of downloads: each member names a URL
and the integrity digest its content must match (<algorithm>-<base64>, told
apart from the URL by shape, so the two may be written in either order).
fetch @dl { package.tgz = "https://…/<sha>" "sha256-…"; }The digest is required: a URL promises nothing about staying the same, so the
declaration is where immutability is claimed and it is checked on every fetch,
before anything is cached. A member is downloaded only when something names it.
@dl denotes the whole set and each member is a file in it, so @dl:name is
the downloaded file and @dl:name:… projects into it — including into an
archive — exactly as a local file of that name would.
repository_group
Section titled “repository_group”targetdef repository_group { * = FILES;}A repository_group serves one package namespace from several registries:
every member is a route — a literal package-name prefix mapped to a declared
registry — and references written against the group resolve together, in one
joint version selection, with each package fetched from the registry its name
routes to. This is how a private registry serving one scope coexists with a
public registry serving everything else:
repository_group @deps { @fortawesome/* = @fa; * = @npm;}A key is a literal name (lodash), a literal with one trailing *
(@fortawesome/*, acme-*), or the bare * — the empty prefix, which is
not a special entry: the longest matching key always wins (an exact name
beating its own name* twin), so exceptions are written as longer prefixes
and declaration order carries no meaning. A name matching no route is simply
not served (there is deliberately no scan or fall-through across registries —
what resolves must never depend on what a registry happens to be missing).
All routed registries must speak the same package ecosystem.
A route’s value may instead be a file set, which is interpreted as a package of the same kind as the rest of the repository group. In this case, the key must be the full name of the package.
Operations: *
targetdef flag { provides = FILES;}A flag yields file content directly, with no build step. Its main use is as
a named switch that a target lists in its deps to opt into some behaviour
(the ts/* source-mode flags are instances of this type); provides may also
expose a computed set of files as the flag’s result.