Stannum/brix/

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

Concepts

A target is a memorized future:

Each target is uniquely identified by its path.

A ruleset is a function that gets a target path 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. This ensures that brix doesn't have to load the scripts for the entire world just to update a single target. When loaded, brix transfers the control to the ruleset. Once the ruleset updates the target successfully, its return value is stored in the database.

If a target X depends on a target Y, the exectution of Y will complete prior to X using the result of Y. A target is out-of-date if it's older than any of its dependencies. A hashed target is out-of-date only if the returned hash differs from the hash in the database. An external 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. External targets are used to model external entities, like source files or environment variables. For example an external target that returns the file's last modified timestamp is the standard way to handle a source file in brix.

Command line interface

Usage:
	brix
	brix <command> [ --<options> ] [ <args> ... ]

Commands:
	build           Update targets.
	clean           Clean targets within prefix.
	dependencies    Print transitive dependencies of the targets.
	explain         Print dependency chain between two targets.
	help            Print this help message.
	info            Print target information from the database.
	list            Print targets within prefix.
	version         Print brix version.
	<none>          Same as `build .`

Options:
	-d <path>       Override the path to the brix database.
	-j <max_jobs>   Set number of parallel jobs to execute.
	-t              Enable times.
	-v <level>      Set verbosity level:
		0               Silent
		1               Print tallies
		2               Print updated targets (default)
		3               Print all targets
		4               Print executed commands
		5               Print maximum information

The build command updates the specified targets, as well as the transitive closure of all the metadeps of those targets.

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 named .brixdb there. An explicit location for the database can be overriden with the -d switch.

Lua binding

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 that directory. 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.directory(s)

Returns the path without the last path element.

string.filename(s)

Returns the last path element.

string.stem(s)

Returns the stem of the last path element.

string.extension(s)

Returns the extension of the last path element.

target(T)

Returns a future for the given target. Adds a dependency on T.

target(T).path

Waits for the future to complete; returns the absolute path of target T.

target(T).result

Waits for the future to complete; returns the result.

Native ruleset

The native ruleset implements sensible defaults for compiling and linking native applications 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 target's 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. Examples of implemented toolsets:

cc
gcc9-d
msvc140d-amd64

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

Rules

name.variant.link

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.

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

name.variant.test-link

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

name.ext.variant.test-object

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

name.run

Executes the output of name.