Manual
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:
- Future—a proxy for a result that is initially unknown, because its computation has not yet finished.
- Memorized—when the computation has finished, the result is saved for future use, until it has to be recomputed.
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.