Stannum

Manual

⚠ 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 rulset implements building native C and C++ applications out-of-the-box. It also serves a reference implementation as for how to implement custom rulsets.

Brix core

Concepts

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 a target without dependencies and 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 time as a hash is the standard way to handle a source file.

Command line interface

Usage:
    brix [ --<options> ] [ build | rebuild ] [ <target> ... ]
    brix [ --<options> ] query [ <target> ... ]
    brix [ --<options> ] dependencies [ <target> ... ]
    brix --version | --help
Options:
    --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
Verbs:
    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.

Database

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 --
end

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 the 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.

string.__div(...)

Joins multiple paths together.

string.extension(s)

Returns the extension of the last path element.

string.stem(s)

Returns the stem of the last path element.

string.filename(s)

Returns the name of the last path element.

target.get(T)

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

target.id(T)

Returns the numerical id of T. This function does not add a dependency on T.

target.artifact(T)

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.

Variants

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 targets name, thus splitting it into different targets. The native ruleset assumes the following naming convention for variants:

toolset[d]-architecture

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.

Rules

name.variant.link

Links name.variant.object and the transitive closure of all of its linkdeps into an executable image.

name.variant.shared

Same as name.variant.link but creates a shared library.

name.variant.library

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

name.ext.variant.object

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.

name.ext.variant.deps

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

Footnotes

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