The barr build process is divided into three distinct stages to ensure incremental efficiency and clean linking.
- Discovery:
-
barrauto identifies sources automatically by default. SpecifyingGLOB_SOURCESorSOURCESwill disable auto scan.
-
Header discovery follows a similar pattern:
AUTO_INCLUDE_DISCOVERYdefaults toon, but can be set toappendoroff. -
Setting
INCLUDESmanually will disable auto-scan for headers, unlessAUTO_INCLUDE_DISCOVERYis set toappend, in which case they are merged. -
Directories with the following patterns are excluded:
"Barrfile", "Makefile", "pyproject.toml", "CMakeLists.txt", "setup.py", "package.json",
"Cargo.toml", "meson.build", "SConstruct", "go.md", ".csproj", "WORKSPACE", "WORSPACE.baze",
"BUILD", "BUILD.bazel", "configure.ac", "build", "bin", "obj", ".git", "cache", ".vs", ".idea", "test",
"CMakeFiles", "Debug", "Release", ".barr", "docs", "assets", "scripts", "modes",
"pycache", ".vscode", "objects", "out", "target", ".svn", ".hg",
"vendor", ".trash"- Additional to this any specified
EXCLUDE_PATTERNS
-
Hashing:
barrruns a 64-bitxxhashon every source file, include file and finally, compiler flags themselves. -
Diffing: it compares these hashes against
.barr/cache/build.cache.
-
Files with matching hashes are skipped.
-
Changed or new files are added to
compile_list.
- Parallel Execution:
barrspawns a Multi-Threaded (MT) pool to compile thecompile_list.
- It invokes the
COMPILERbased on the configuration specified inBarrfile, producing.oobject files.
barr uses an intermediate archiving step:
-
Bundles all objects except
MAIN_ENTRYinto a local static library:libbarr.a. -
Why? This makes the final stage faster, more organized, and ensures the core logic is treated as a single unit.
The final binary is produced by LINKER (e.g: ld, lld, mold):
-
It links
MAIN_ENTRYobject ,libbarr.a, any specifiedMODULES(built earlier) and systempkgsfound byfind_package. -
TARGET: The resulting binary is placed inOUT_DIR.
To show how barr handles libraries for system installs, lets look at a project called foo.
- The library structure:
Headers should be separated into a public
includedirectory. This allowsbarrto install them correctly without mixing private source files.
.
├── Barrfile
├── include/ <-- Public API
│ ├── foo.h
│ └── io.h
└── src/core/ <-- Implementation
└── foo.c- The Installation Phase
When you runsudo barr installon a project withTARGET_TYPE=static(orshared),barrmaps your project to your system hierarchy:
$ sudo barr install
[barr_log]: Prefix defaulted to: /usr/local
[barr_log]: Installing include directory: .../foo/include -> /usr/local/include/foo
[barr_log]: Installing library: .../libfoo.a -> /usr/local/lib/libfoo.a
[barr_log]: Added to manifest: /usr/local/include/foo
[barr_log]: Added to manifest: /usr/local/lib/libfoo.a
[barr_log]: Install complete- Using the Installed Library
Now, any other project on your system can use foo just like a standard system library.
The source (main.c):
Note the name-spaced include <foo/foo.h>. This is possible because barr installed your headers into a subdirectory named after the project.
#include <foo/foo.h>
int main(void) {
foo_printf("Hello from foo-barr\n");
return 0;
}Since /usr/loca/include and /usr/local/lib are standard paths for GCC/Clang on Linux, you just need to tell the linker to look for foo:
TARGET = "my_app";
LFLAGS = "-lfoo";
# We explicitly include the library path because some linkers (like lld)
# may not search /usr/local/lib by default.
LIB_PATHS = "-L/usr/local/lib"; --prefix: defines the final install location on the system (default: /usr/local).
--destdir: adds a temporary staging root in front of that location.
Example: Installing and executable
Assume:
TARGET_TYPE = "executable"
TARGET = "my_app"Normal Install
sudo barr install # installs to /usr/local by defaultResult:
/usr/local/bin/my_appStaged Install
barr install --destdir ./pkgroot/ --prefix usrResult:
./pkgroot/usr/bin/my_appNotice:
final_path = DESTDIR + PREFIX + bin/my_appUninstall Behavior
While installing barr writes to project's .barr/data/install_info file.
At uninstall, it will read the info file and remove exactly those files.
The module system allows one barr project to build and integrate another barr project as part of the same build flow.
A module is simply another directory containing its own Barrfile. When declared, barr will:
-
Invoke a nested
barr buildinside that directory. -
If the module is required the parent build process will fail.
Inside your Barrfile:
add_module("foo","tools/foo","no"); # name, path to directory, required? Arguments:
name = Logical module name (for registry)
path = Directory containing the module's Barrfile
required = Optional: "true","yes" or "required"
Only first two arguments are mandatory.
If required is omitted, the module is treated as optional.
.
├── Barrfile
├── src/
│ └── main.c
└── tools/
└── foo/
├── Barrfile
└── src/
└── foo.cWhen barr encounters"
add_module("foo","tools/foo","yes"); It performs:
barr build --dir tools/fooBehavior:
-
If the module builds successfully → it is registered and integrated.
-
If it fails and is required → the parent build fails.
-
If it fails and is optional → the parent build continues.
Root Barrfile:
TARGET = "app";
TARGET_TYPE = "executable";
add_module("math", "modules/math", "required");modules/math/Barrfile:
TARGET = "math";
TARGET_TYPE = "static";Build flow:
- Root build starts
modules/mathis built- If successful -> root continues
- If failed and required -> root aborts