b(1)
πΈ b(1) β General Commands Manual πΈ
okay so bestie, welcome to b(1), straight out of the General Commands Manual, and it's the build2 build system driver and it's a lot and I love it here π
β¨ NAME β¨
b β build system driver π οΈ
π¦ SYNOPSIS π¦
b --help
b --version
b [options] [variables] [buildspec]
buildspec = meta-operation(operation(target...[,parameters])...)...
π DESCRIPTION π
The build2 build system driver runs a whole set of meta-operations on operations on targets, all according to the build specification β or buildspec, for short, because we're cute like that. And you get to steer the whole thing by handing it driver options and build system variables. π
ngl the ordering rules are extremely chill: options, variables, and buildspec fragments can show up in any order. But heads up π β if an argument starts with - and you don't want it read as an option, drop the -- separator. And if an argument contains = and you don't want it read as a variable, add the second -- separator. Two separators, two whole vibes, no cap.
Every single component in the buildspec can be left out, and the defaults just quietly handle it:
- no meta-operation? it defaults to
perform. - no operation? it defaults to the default operation for that meta-operation. For
performthat'supdate. - no target? it defaults to the current working directory.
A meta-operation on an operation is called an action, periodt. And some operations and meta-operations take extra parameters. For example:
$ b # perform(update(./))
$ b foo/ # perform(update(foo/))
$ b foo/ bar/ # perform(update(foo/ bar/))
$ b update # perform(update(./))
$ b 'clean(../)' # perform(clean(../))
$ b perform # perform(update(./))
$ b configure # configure(?(./))
$ b 'configure(../)' # configure(?(../))
$ b clean update # perform(clean(./) update(./))
$ b configure update # configure(?(./)) perform(update(./))
$ b 'create(conf/, cxx)' # create(?(conf/), cxx)
Notice that question mark ? β that's the notation showing the (imaginary) default operation for the configure meta-operation. For configure, the default operation is "all operations". So like, it configures all the operations for whatever target you pointed at. π«
You can also generate multiple operations for the same set of targets. Compare these two, they do the same thing:
$ b 'clean(foo/ bar/)' 'update(foo/ bar/)'
$ b '{clean update}(foo/ bar/)'
And here are some more genuinely useful buildspec examples, bookmark them:
$ b '{clean update}(...)' # rebuild
$ b '{clean update clean}(...)' # make sure builds
$ b '{clean test clean}(...)' # make sure passes tests
$ b '{clean disfigure}(...)' # similar to distclean
okay so in POSIX shells, parentheses are special characters π and they have to be quoted whenever you use them in a buildspec. Which is annoying on its own, but the real crime is that quoting also kills path auto-completion. So to save us, there's a shortcut syntax for running a single operation or meta-operation. For example:
$ b clean: foo/ bar/ # clean(foo/ bar/)
$ b configure: src/@out/ # configure(src/@out/)
$ b create: conf/, cxx # create(conf/, cxx)
$ b configure: config.cxx=g++ src/ # configure(src/) config.cxx=g++
To activate the shortcut syntax, the first buildspec argument has to start with an operation or meta-operation name and end with a colon (:). To turn it back into normal buildspec syntax, that colon gets replaced with the opening parenthesis ((), the rest of the buildspec arguments are treated as-is, and the final closing parenthesis ()) gets added at the end. chef's kiss, it's giving magic trick β¨
For each target, the driver expects to find buildfile either in the target's own directory, or β if that directory is part of the out tree (out_base) β in the corresponding src directory (src_base). π¦
For example, assuming foo/ is the source directory of a project:
$ b foo/ # out_base=src_base=foo/
$ b foo-out/ # out_base=foo-out/ src_base=foo/
$ b foo-out/exe{foo} # out_base=foo-out/ src_base=foo/
The one exception to that rule is a directory target π― β in that case, as long as the directory has subdirectories, an implied buildfile with the following content is just assumed to exist:
# Implied directory buildfile: build all subdirectories.
#
./: */
Now, in the example above, we were lowkey assuming the driver could figure out the association between out_base and src_base all by itself. When src_base and out_base are not the same directory, that association happens one of two ways: the config module (which implements the configure, disfigure, and create meta-operations) saves that association as part of the configuration process. But if the association hasn't been saved? Then we have to spell out src_base explicitly using this extended target syntax:
src-base/@target
Continuing with the previous example:
$ b foo/@foo-out/exe{foo} # out_base=foo-out/ src_base=foo/
Normally you'd only need to specify src_base explicitly once, during configuration. A typical usage looks like:
$ b configure: foo/@foo-out/ # src_base is saved
$ b foo-out/ # no need to specify src_base
$ b clean: foo-out/exe{foo} # no need to specify src_base
Besides in-source and out-of-source builds, build2 also supports configuring a project's source directory as forwarded to an out-of-source build. With that forwarded configuration in place, if we run the build system driver from the source directory, it'll automatically build in the output directory and backlink (using symlinks or another suitable mechanism) certain "interesting" targets β executables, documentation, etc β back to the source directory so they're easy to get to. Continuing with the previous example:
$ b configure: foo/@foo-out/,forward # foo/ forwarded to foo-out/
$ cd foo/
$ b # build in foo-out/
$ ./foo # symlink to foo-out/foo
The ability to specify build2 variables right on the command line is normally used to pass configuration values, like:
$ b config.cxx=clang++ config.cxx.coptions=-O3
And similar to the buildspec situation, POSIX shells often inhibit path auto-completion on the right hand side of a variable assignment π. To help with that, the assignment can be broken down into three separate command line arguments, like:
$ b config.import.libhello = ../libhello/
The build system has the following built-in and pre-defined meta-operations π:
π perform
Perform an operation.
π configure
Configure all operations supported by a project and save the result in the project's build/config.build file. Implemented by the config module. For example:
$ b configure \
config.cxx=clang++ \
config.cxx.coptions=-O3 \
config.install.root=/usr/local \
config.install.root.sudo=sudo
Use the forward parameter to instead configure a source directory as forwarded to an out-of-source build. For example:
$ b configure: src/@out/,forward
π disfigure
Disfigure all operations supported by a project and remove the project's build/config.build file. Implemented by the config module.
Use the forward parameter to instead disfigure forwarding of a source directory to an out-of-source build. For example:
$ b disfigure: src/,forward
π create
Create and configure a configuration project. Implemented by the config module. π
Normally a build2 project gets created manually β you write the bootstrap.build and config.build files, add source files, and so on. But there's a special kind of project, which we call a configuration project, that's often super useful. Such a project doesn't have any source files of its own. Instead, it acts as an amalgamation for building other projects as part of it. Doing it this way has two major benefits, and they're both good:
- sub-projects automatically resolve their imports to other projects in the amalgamation
- sub-projects inherit their configuration from the amalgamation β which means if we want to change something, we only have to do it in one place π«Ά
As an example, let's say we have two C++ projects: the libhello library in libhello/, and the hello executable that imports it in hello/. And we want to build hello with clang++.
One way to do it would be to configure and build each project in its own directory, for example:
$ b configure: libhello/@libhello-clang/ config.cxx=clang++
$ b configure: hello/@hello-clang/ config.cxx=clang++ \
config.import.libhello=libhello-clang/
The two drawbacks, as mentioned above, are the need to explicitly resolve the import, and having to make changes in multiple places if we ever want to switch, say, from clang++ to g++. π
But we can get the exact same end result with none of those drawbacks using the configuration project:
$ b create: clang/,cxx config.cxx=clang++ # Creates clang/.
$ b configure: libhello/@clang/libhello/
$ b configure: hello/@clang/hello/
The targets passed to the create meta-operation must be directories, and those directories should either not exist or be empty. For each such directory, create first initializes a project as described below, and then configures it by executing the configure meta-operation.
The first optional parameter to create is the list of modules to load in root.build. By default, create appends .config to the names of these modules, so that only their configurations get loaded. You can override this behavior by specifying the period (.) after the module name. You can also tell create to use the optional module load by prefixing the module name with the question mark (?).
The second optional parameter is the list of modules to load in bootstrap.build. If it's not specified, then the test, dist, and install modules are loaded by default. The config module is always loaded first.
Besides creating the project's bootstrap.build and root.build, create also writes the root buildfile with the following contents:
./: {*/ -build/}
If used, this buildfile will build all the sub-projects currently present in the configuration. π
π dist
Prepare a distribution containing all files necessary to perform all operations in a project. Implemented by the dist module.
π info
Print basic information (name, version, source and output directories, etc) about one or more projects to stdout, separating multiple projects with a blank line. Each project is identified by its root directory target. For example (some output is omitted):
β¨ and that's where part 1 wraps up β more coming, don't go anywhere π«
$ b info: libfoo/ libbar/
project: libfoo
version: 1.0.0
src_root: /tmp/libfoo
out_root: /tmp/libfoo
subprojects: @tests
project: libbar
version: 2.0.0
src_root: /tmp/libbar
out_root: /tmp/libbar-out
subprojects: @tests
Ok so if you want to skip all that subproject discovering and printing, hit it with the no_subprojects parameter, like:
$ b info: libfoo/,no_subprojects
And if you'd rather have it in JSON instead, use the json parameter:
$ b info: libfoo/,json
In that case what you get back is a JSON array of objects, and each object is the serialized version of this C++ struct, project_info:
struct subproject
{
string path;
optional<string> name;
};
struct project_info
{
optional<string> project;
optional<string> version;
optional<string> summary;
optional<string> url;
string src_root;
string out_root;
optional<string> amalgamation;
vector<subproject> subprojects;
vector<string> operations;
vector<string> meta_operations;
vector<string> modules;
};
Like, for example:
[
{
"project": "libfoo",
"version": "1.0.0",
"summary": "libfoo C++ library",
"src_root": "/tmp/libfoo",
"out_root": "/tmp/gcc-debug/libfoo",
"amalgamation": "..",
"subprojects": [
{
"path": "tests"
}
],
"operations": [
"update",
"clean",
"test",
"update-for-test",
"install",
"uninstall",
"update-for-install"
],
"meta-operations": [
"perform",
"configure",
"disfigure",
"dist",
"info"
],
"modules": [
"version",
"config",
"test",
"install",
"dist"
]
}
]
π Peep the JSON OUTPUT section further down for the deets on how this format behaves overall and what the struct serialization actually means.
the built-in + pre-defined operations β¨
The build system ships with these, and they are iconic:
updateβ Update a target.cleanβ Clean a target.testβ Test a target. Runsupdateas a pre-operation. Implemented by thetestmodule.update-for-testβ Update a target for testing. This one is literally equivalent to theupdatepre-operation as executed by thetestoperation, so you can use it when you only wanna update the stuff that testing actually needs. Implemented by thetestmodule.installβ Install a target. Runsupdateas a pre-operation. Implemented by theinstallmodule.uninstallβ Uninstall a target. Runsupdateas a pre-operation. Implemented by theinstallmodule.update-for-installβ Update a target for installation. This is equivalent to theupdatepre-operation as executed by theinstalloperation, so it's your girl when you only wanna update what installation needs. Implemented by theinstallmodule.
Heads up bestie π«Ά:buildspecand command line variable values are treated as buildfile fragments, which means they can do quoting and escaping, and they can contain variable expansions and evaluation contexts. BUT β to keep things usable across all the different platforms, escaping in these two situations is limited to the effective sequences of\',\",\\,\$, and\(, with all other sequences interpreted as is. Together with double-quoting that's enough to represent any value. No cap. For example:
$ b config.install.root=c:\projects\install
$ b "config.install.root='c:\Program Files\test\'"
$ b 'config.cxx.poptions=-DFOO_STR="foo"'
β¨ OPTIONS β¨
-vβ Print the actual commands being executed. This is equivalent to--verbose 2.-Vβ Print all the underlying commands being executed. Equivalent to--verbose 3.--quiet,-qβ Run quietly, only printing error messages in most contexts. In certain contexts (like while updating build system modules) this verbosity level may get ignored. If you want quiet everywhere, use--silent. This option is equivalent to--verbose 0.--silentβ Run quietly, only printing error messages in all contexts.--verboselevel β Set the diagnostics verbosity to level between0and6. Level0disables any non-error messages (but go peep the difference between--quietand--silent) while level6produces so much info, with level1being the default. Here's the extra diagnostics you get at each level:- High-level information messages.
- Essential underlying commands being executed.
- All underlying commands being executed.
- Information that could be helpful to the user.
- Information that could be helpful to the developer.
- Even more detailed information.
--statβ Display build statistics.--progressβ Display build progress. If you're printing to a terminal, progress is displayed by default for low verbosity levels. Use--no-progressto suppress it.--no-progressβ Don't display build progress.--diag-colorβ Use color in diagnostics. If printing to a terminal, color is used by default provided the terminal is not dumb. Use--no-diag-colorto suppress. This option affects the diagnostics printed by the build system itself. Some rules may also choose to propagate its value to the tools they invoke (compilers and such π).--no-diag-colorβ Don't use color in diagnostics.--jobs,-jnum β Number of active jobs to perform in parallel. This counts both the active threads inside the build system and the external commands (compilers, linkers, etc) that have been started but haven't finished yet. If you don't specify this option, or you specify it with the0value, then the number of available hardware threads gets used. π§--max-jobs,-Jnum β Maximum number of jobs (threads) to create. Default is8xthe number of active jobs (--jobs/-j) on 32-bit architectures and32xon 64-bit. See the build system scheduler implementation for the details.--queue-depth,-Qnum β The queue depth as a multiplier over the number of active jobs. Normally you want a deeper queue if the jobs take long (compilation, for example) and a shorter one if they're quick (simple tests, for example). The default is4. See the build system scheduler implementation for the details.--file-cacheimpl β File cache implementation to use for intermediate build results. Valid values arenoop(no caching or compression) andsync-lz4(no caching with synchronous LZ4 on-disk compression). If you don't specify this option, then a suitable default implementation is used (currentlysync-lz4).--max-stacknum β The maximum stack size in KBytes to allow for newly created threads. On pthreads-based systems the driver queries the stack size of the main thread and uses that same size when creating additional threads. That lets you adjust the stack size using familiar mechanisms likeulimit. Sometimes though, the main thread's stack size is excessively large π. So the driver checks if it's greater than a predefined limit (64MBon 64-bit systems and32MBon 32-bit ones) and caps it to a more sensible value (8MB) if that's the case. This option lets you override that check with the special zero value, which means the main thread stack size should be used as is.--serial-stop,-sβ Run serially and stop at the first error. This mode is useful for investigating build failures caused by build system errors rather than compilation errors. Note that if you don't wanna keep going but still want parallel execution, add--jobs/-j(for example-j 0for default concurrency). Also note that during serial execution there's no diagnostics buffering and the child process' stderr is a terminal (unless redirected; see--no-diag-bufferfor the deets).--dry-run,-nβ Print commands without actually executing them. Note that commands required to create an accurate build state will still be executed, and the extracted auxiliary dependency information gets saved. In other words, this is not the "don't touch the filesystem" mode, it's more like "do the minimum amount of work to show what needs to be done". Also note that only theperformmeta-operation supports this mode.--no-diag-bufferβ Do not buffer diagnostics from child processes. By default, unless running serially, that diagnostics gets buffered and printed all at once after each child exits, so it doesn't interleave. But that has side-effects, because the child process' stderr is no longer a terminal π. Most notably, the use of color in diagnostics may get disabled by some programs. On the other hand, depending on the platform and the programs invoked, the interleaving diagnostics may not break lines and thus could be tolerable.--match-onlyβ Match the rules without executing the operation. This mode is primarily useful for profiling and dumping the build system state.--load-onlyβ Match the rules only toalias{}targets, ignoring other targets and without executing the operation. In particular, this has the effect of loading all the subdirectory buildfiles that aren't explicitly included. Note that this option can only be used with theperform(update)action on analias{}target, usuallydir{}.--no-external-modulesβ bestie, this one says nope to loading external modules during project bootstrap. Important caveat though: you can only use it with meta-operations that don't load the project's buildfiles β stuff likeinfo. So don't try it on the heavy ones, she won't go π--structured-resultfmt β write the result of execution in a structured form β¨. In this mode, instead of printing diagnostics about what happened to the targets to stderr, the driver writes a machine-readable result description to stdout in whatever format you picked. Valid values for fmt arelinesandjson. Heads up: right now only theperformmeta-operation supports structured result output. π«Ά
If the output format is lines, you get one line per buildspec action/target pair, looking like this:
state meta-operation operation target
Where state is one of unchanged, changed, or failed. And if the action is a pre or post operation, then the outer operation shows up in parenthesis. Like, for example:
unchanged perform update(test) /tmp/hello/hello/exe{hello}
changed perform test /tmp/hello/hello/exe{hello}
If the output format is json, you get a JSON array of objects β basically the serialized glow-up of this C++ struct, target_action_result:
struct target_action_result
{
string target;
string display_target;
string target_type;
optional<string> target_path;
string meta_operation;
string operation;
optional<string> outer_operation;
string state;
};
For example:
[
{
"target": "/tmp/hello/hello/exe{hello.}",
"display_target": "/tmp/hello/hello/exe{hello}",
"target_type": "exe",
"target_path": "/tmp/hello/hello/hello",
"meta_operation": "perform",
"operation": "update",
"outer_operation": "test",
"state": "unchanged"
},
{
"target": "/tmp/hello/hello/exe{hello.}",
"display_target": "/tmp/hello/hello/exe{hello}",
"target_type": "exe",
"target_path": "/tmp/hello/hello/hello",
"meta_operation": "perform",
"operation": "test",
"state": "changed"
}
]
Peep the JSON OUTPUT section below for the deets on this format's overall properties and how the struct serialization actually works, iykyk π
So the members, one by one:
targetβ the target name, qualified with the extension (if that applies) and, if needed, quoted so you can hand it right back to the build system driver on the command line.display_targetβ the unqualified, unquoted "display" target name, same vibe as in thelinesformat.target_typeβ the type of the target.target_pathβ an absolute path to the target, but only if the target type is path-based ordir.
--mtime-checkβ do file modification time sanity checks π΅οΈ. These checks are lowkey helpful for diagnosing spurious rebuilds, and they're enabled by default on Windows (which, iconic behavior, is known not to guarantee monotonically increasing mtimes) and for the staged version of the build system on other platforms. Wanna turn it off? Use--no-mtime-check.--no-mtime-checkβ don't do file modification time sanity checks. See--mtime-checkfor the details, bestie.--dumpphase β dump the build system state after the phase you name. Valid phase values areload(after loading buildfiles) andmatch(after matching rules to targets). Thematchvalue also hasmatch-preandmatch-postvariants for dumping the state of the pre/post-operations (matchdumps the main operation only, no cap). Repeat this option to dump state after multiple phases/variants. By default the entire build state gets dumped, but you can change that with the--dump-scopeand--dump-targetoptions. Also see--match-onlyand--load-only. π--dump-formatformat β the representation format and output stream to use when dumping the build system state. Valid values arebuildfile(a human-readable, Buildfile-like format written to stderr β this is the default β¨) andjson-v0.1(machine-readable, JSON-based format written to stdout). For the buildfile format deets, see Diagnostics and Debugging (#intro-diag-debug). For thejson-v0.1format, see the JSON OUTPUT section below (overall properties) and JSON Dump Format (#json-dump) (format specifics). Ngl, the JSON format is currently unstable (hence that temporary-v0.1suffix π).
Also important: because it's totally possible to end up with multiple dumps (like, by passing --dump-scope and/or --dump-target multiple times), the JSON output comes in "JSON Lines" form β that means no pretty-printing, and the top-level JSON objects are delimited by newlines. And heads up: if the JSON dump output gets combined with --structured-result=json, then the structured result is the last line. π
--dump-scopedir β dump the build system state for just that one dir scope. Repeat this option to dump multiple scopes. π--dump-targettarget β dump the build system state for just that one target. Repeat this option to dump multiple targets.--trace-matchtarget β trace rule matching for the target you name. This is mainly useful when you're troubleshooting π. Repeat this option to trace multiple targets.--trace-executetarget β trace rule execution for the target you name. Again, primarily a troubleshooting thing π. Repeat this option to trace multiple targets.--no-columnβ don't print column numbers in diagnostics. Simple as that.--no-lineβ don't print line and column numbers in diagnostics.--buildfilepath β the alternative file to read build information from. Default isbuildfileorbuild2file, depending on the project's build file/directory naming scheme. If path is-, then read from stdin. Note: this option only affects the files read as part of the buildspec processing. Specifically, it has no effect on thesourceandincludedirectives. Because of that, this option is primarily intended for testing rather than actually renaming build files in real projects. π--config-guesspath β the path to theconfig.guess(1)script that should be used to guess the host machine triplet. If you don't specify this option, thenbfalls back on using the target it was built for as host.--config-subpath β the path to theconfig.sub(1)script that should be used to canonicalize machine triplets. If you don't specify this option, thenbuses its built-in canonicalization support, which should be enough for commonly-used platforms. β¨--pagerpath β the pager program used to show long text. Commonly-used pagers arelessandmore. You can also pass extra options to the pager program with--pager-option. If you specify an empty string as the pager program, then no pager will be used. And if you don't explicitly specify a pager program, thenbwill try to uselessβ and if that's not available, then no pager for you. π«Ά--pager-optionopt β an additional option to pass to the pager program. See--pagerfor more info on the pager program itself. Repeat this option to specify multiple pager options.--options-filefile β read additional options from file. Each option should sit on its own line, optionally followed by a space or an equal sign (=) and an option value. Empty lines and lines starting with#are ignored (self-care π ). Option values can be wrapped in double (") or single (') quotes to preserve leading and trailing whitespaces and to specify empty values. And if the value itself contains trailing or leading quotes, enclose it with an extra pair of quotes, for example'"x"'. Non-leading and non-trailing quotes are interpreted as being part of the option value, fr fr.
The semantics of putting options in a file are equivalent to providing that same set of options in the same order on the command line at the exact point where the --options-file option shows up β except that shell escaping and quoting is not required. Repeat this option to specify more than one options file. πΈ
--default-optionsdir β the directory to load additional default options files from.--no-default-optionsβ don't load default options files. Periodt.--helpβ print usage information and exit. π--versionβ print version and exit.
π DEFAULT OPTIONS FILES π
okay so instead of inventing a whole separate config file format just for tool configuration, the build2 toolchain is like "no babe, we're reusing" β it uses default options files, and those files contain the exact same options you could just type on the command line. They're basically like the options files you'd hand over with --options-file, except the difference is they get loaded by default. Sneaky? A little. Convenient? Extremely. β¨
For the build system driver, these default options files are called b.options and the search happens in the .build2/ subdirectory of your home directory, plus the system directory (think /etc/build2/) if that's been configured. And heads up bestie β these files aren't only for options, they can also carry global variable overrides. Multitasking queen. π
Once the search is done, the files get loaded in reverse order, meaning: system directory first (if there is one), then the home directory, and finally the options you typed on the command line. So it's going from the most generic to the most specific, and the command line always gets the last word β it can override anything the default options files said. Main character energy, honestly. π
If one of these default options files contains --no-default-options, the search just stops at the directory holding that file and no outer files get loaded. And if you put --no-default-options on the command line itself? Then literally none of the default options files get searched for or loaded. Zero. Nada. π«
You can also point at an extra directory full of default options files with --default-options. Its configuration files get loaded after the home directory. Cute little extra layer. π
Wanna see the order things load in? That's traced at verbosity level 3 (the -V option) or higher. Watch it happen live, it's giving behind-the-scenes documentary. π¬
π JSON OUTPUT π
Commands that support JSON output describe their formats as a serialized representation of a C++ struct β or an array of them. For example:
struct package
{
string name;
};
struct configuration
{
uint64_t id;
string path;
optional<string> name;
bool default;
vector<package> packages;
};
And here's what the serialized JSON for struct configuration looks like:
{
"id": 1,
"path": "/tmp/hello-gcc",
"name": "gcc",
"default": true,
"packages": [
{
"name": "hello"
}
]
}
This section spills the tea on the overall properties of these formats and how struct serialization actually works. β
The order of members in a JSON object is fixed, exactly as specified in the corresponding struct. New members might get added in the future (and older consumers should just ignore them, be chill about it), but the semantics of the existing members may not change β and yes, that includes whether the top-level entry is an object or an array. Locked in. π
An object member is required unless its type is optional<>, bool, or vector<> (array). For bool members, absent means false. For vector<> members, absent means empty. And an empty top-level array is always present. no cap. π―
So like, the following JSON text is a totally valid possible serialization of that configuration struct up there:
{
"id": 1,
"path": "/tmp/hello-gcc"
}
See how name, default, and packages justβ¦ dipped? That's the optional/bool/vector thing doing its thing. π¦
π«Ά EXIT STATUS π«Ά
Non-zero exit status is returned in case of an error. That's it, that's the whole vibe. π
πΈ ENVIRONMENT πΈ
HOMEβ used to figure out the user's home directory. If it's not set, thengetpwuid(3)gets called instead. This value is what lets diagnostics shorten paths by swapping your home directory for~/β so cute, so tidy. It's also made available to buildfiles as thebuild.homevariable. πBUILD2_VAR_OVRβ used to propagate global variable overrides down into nested build system driver invocations. Its value is a list of global variable assignments, separated with newlines.BUILD2_DEF_OPTβ used to suppress loading of default options files in nested build system driver invocations. Its values arefalseor0to suppress, andtrueor1to load.
π BUGS π
Send bug reports to the users@build2.org mailing list. They're nice, I promise. π₯Ί
π COPYRIGHT π
Copyright (c) 2014-2024 the build2 authors.
Permission is granted to copy, distribute and/or modify this document under the terms of the MIT License.
and that's a wrap on the whole b(1) page bestie!! π this was build2 0.17.0, dated June 2024, and it's the b(1) manual β go forth and build, you absolute icon π
β¨π¦
π¦ where this page comes from
- fedora 43: build2 0.17.0-5.fc43 Β· MIT
- fedora 44: build2 0.17.0-7.fc44 Β· MIT
- nixos 26.05: build2 0.17.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms