⚠ Work in progress ⚠

Brix consists of two parts: the brix core and the native ruleset. Brix core is responsible for maintaining a database of targets, tracking their status, and routing their invocation to the build scripts in the source tree. The native ruleset implements building native C and C++ applications out-of-the-box. It also serves as a reference implementation for how to implement custom rulsets.

Brix core


A target is a memorized future:

Each target is uniquely identified by its path. Note that targets are not files, and their paths do not have to map to existing files.

A ruleset is a function that gets a path of a target as a parameter and performs the necessary computation to update the target. Brix looks for a file named brixfile in each of the parent directories of a target to load the ruleset responsible for that target.[1] When loaded, brix transfers the control to the ruleset. Once the ruleset updates the target successfully, its return value is stored in a database.

A target depends on another target if it uses the result of that other target. A target is out-of-date if any of its dependencies are out-of-date. A hashed target is out-of-date only if the returned hash differs from the hash in the database. A phony target is updated unconditionally.

Hashed targets are used when the target depends only on a part of the result of its dependencies. For example a target that builds an index from a set of documents can be hashed. If the documents are changed in a way that does not affect the index then the index will be recomputed but its dependents will remain up-to-date. Hashed phony targets are used to model external entities, like source files or environment variables. For example a hashed phony target that returns the file's last modified timestamp is the standard way to handle a source file in brix.

Command line interface

    brix [ --<options> ] [ build | rebuild ] [ <target> ... ]
    brix [ --<options> ] query [ <target> ... ]
    brix [ --<options> ] dependencies [ <target> ... ]
    brix --version | --help
    --trace-exec    Traces all execs
    --trace-invoke  Traces all invokes
    --verbose       Traces everything
    -h --help       Print this help message
    --version       Print out the brix version
    --[no-]print-ids  Prints target ids
    --db <path>     Overrides the path to the brix database
    build           Brings target(s) up to date (default).
    rebuild         Rebuilds target(s) and all their dependencies.
    query           Prints target(s) information from the database.
    dependencies    Prints all phony dependencies of the target(s) (recursive).

When brix is launched with no targets specified the default . target is assumed.


Brix caches the state of the targets in a database. By default it finds the top-most parent directory of the current working directory that has a brixfile in it and puts the database in a tmp/ subdirectory within. An explicit location for the database can be overriden with the --db argument;

Lua binding

At the moment brix assumes that rulesets are implemented in Lua. Brix may load the ruleset multiple times during the build. The return value of the main chunk must be a callable that implements the ruleset:

return function(p)
	-- update target p --

The target path p is relative to the ruleset directory, which is accessible by os.getcwd. All brix functions listed below resolve paths relative to that directory.

The Lua binding expeting a target as input can recieve any of

All strings are UTF-8. All paths use forward slashes on all platforms. Brix adds some path manipulation functions to the Lua string type.


Joins multiple paths together.


Returns the extension of the last path element.


Returns the stem of the last path element.


Returns the name of the last path element.


Adds a dependency on T, waits for it to complete and returns the result.


Adds a dependency on T, waits for it to complete and returns the first artifact:

Native ruleset

The native ruleset implements sensible defaults for compiling and linking C and C++ on supported platforms.


Brix supports building multiple variants (aka configurations) simultaneously. In order to distinguish between same target built in different variants, the variant is encoded as part of the target's name, thus splitting it into different targets. The native ruleset assumes the following naming convention for variants:


Then it infers the toolset to use and the flags to pass to the compiler and linker from that.

Rulesets extending the native ruleset can add extra variants as they wish.


Find an existing file name.ext where ext is one of the source extensions. Links name.ext.variant.object and the transitive closure of all of its linkdeps into an executable image.


Same as but creates a shared library.


Same as but creates an archive (a static library).


Compiles name.ext into an object file. The compiler to use is automatically inferred from the ext.

Invokes name.ext.variant.deps and computes the transitive closure of all its objdeps.


Returns the compile time and the link time dependencies of name.ext.

With header based dependency inferences enabled injects a dependency on a.c if a.h is included


Same as but replaces dependencies on name.ext.variant.object with dependencies on name.ext.variant.test-object.


Same as name.ext.variant.object but defines BRIX_TEST=1.

Executes the artifact of name.


  1. This ensures that brix doesn't have to load the scripts for the entire world just to update a single target.