Execution¶
To see an overview of all command line options, run buildsome --help
. This
document will focus on most significant aspects of the command line options,
and operation around building.
Specifying targets¶
One or more target can specified at the command line, or none at all (explained here);
buildsome
Or:
buildsome some-file-to-build subdir/some/nested/target
Or from inside a subdirectory:
cd subdir/some
buildsome nested/target
By default, Buildsome
regards the directory containing the top-most
Buildsome.mk
as the root dir, and always starts evaluating the
target tree from there. Additionally, running buildsome
without specifying
targets, while in any sub-directory, is equivalent to trying to build
the default
target in that sub-directory.
Building in sub-directory while being in it, or outside of it¶
It may be confusing that passing a source directory to buildsome
as
a target does nothing. That happens because the directory itself
already exists, so nothing needs to be done. Instead, if one defines a
default
target in a subdirectory, it would make more sense to pass
that target explicity, e.g. buildsome subdir/default
.
Output format¶
Buildsome makes an effort to tell why a target is being built. There could be various reasons:
- Rebuild due to changes in the content or meta-data of an input.
T141 Execution log of ["src/.objs/Class.c.release.o"] did not match because input(content): change: "src/Class.c"
T141 { ["src/Class.o"] BUILDING (BecauseSpeculative (BecauseHooked AccessDocEmpty))
- Output is missing
T093 Execution log of ["src/Class.o"] did not match because output file was deleted: "src/Class.o"
T093 { ["src/Class.o"] BUILDING (BecauseSpeculative (BecauseHooked AccessDocEmpty))
- Rebuild due to changes in the evaulated target script.
T093 { ["src/Class.o"] BUILDING (BecauseSpeculative (BecauseHooked AccessDocEmpty))
(TODO: it does not explicitly say that a target script was changed. This needs fixing).
Execution warnings¶
Over-specified inputs¶
If a target depends on a file explicitly in the definition, but does not make use of that file as an input during execution, this warning is emitted. It is important for targets to confirm to their minimal specification
Execution errors¶
Various errors are encountered by users of Buildsome. The following is a summary of the major ones, and detailed explaination.
ThirdPartyMeddlingError¶
Prior to letting target running under Buildsome to open their dependencies, Buildsome checks the modification time of the input files at the leaf of the dependencies tree. If any of these sources files change during the, this error is emitted.
This feature is meant to detected accidental user edits during execution. Without this build, in a compilation which consists of several files may result in an invalid build, because some of the targets received inputs that don't match the inputs of other targets. This is especially valid for C headers, for example.
TargetCommandFailed¶
This error indicates that one of the target scripts returned a non-zero status code and likely failed. For example, this is the UNIX behavior to signify process execution failure.
UnregisteredOutputFileExists¶
Because Buildsome tracks the output files of all targets (removing the necessity of manually maintaing a old fashioned 'clean' target), then it mindful about finding files that were not created by any target in a previous invocation.
This could happen if Buildsome is executed and for some reason later,
the database that it maintains to track executions gets deleted. The
database is Buildsome.mk.db
, and it resides at the top directory,
where Buildsome.mk
is located. It is possible to provide the
--overwrite
switch in that case, to suppress this behavior. It
should not be the default way of executing Buildsome, in any case.
TargetDependencyLoop¶
When Buildsome detects that a target directly or indirectly depends on itself, whether implicitly or explicitly, this error is emitted. Note that directory listing by processes introduces a dependency over the directory that is being listed. If the same process also modifies that directory, it would constitued a dependency loop.
Parallelism¶
It is possible to pass a -j
parameter that determines the number of
jobs to run in parallel. Note that it does not serve as a hard limit,
because it is possible that jobs would be temporarily stopped
mid-execution in order to satisfy dependencies, so -j
comes to serve
as a limit to the number of jobs currently not waiting for any
dependency.
Bypassing automatic dependency detection¶
Under Buildsome, certain types of targets are problematic. For example,
targets that maintain their own caching, meaning they arbitrarily read
inputs from a previous invocation. You may find the complex 'do-all'
tools such as go build
(of the Go language), mvn
(Maven), or ccache
may behave in such a way.
It is possible to suppress the dependency scanning of Buildsome by
overriding the LD_PRELOAD
variable during target execution.
NOTE: One must be careful when doing so, because it means that inputs would not be detected, and later, unbeknownst to the developer, actual dependencies would not match the specification that Buildsome infers, regressing back to gmake-like hell.
Example pattern for dependency detection bypass¶
Suppose we have a program named problematic-command
which performs
problematic file system accesses during its execution. Suppose that
we know for a fact that it only reads to inputs input-a
and input-b
.
In that case, we can use shell script to let it execute under Buildsome, but still hint Buildsome regarding the outputs and inputs of the whole target, using file accesses of our own. Our shell script can appear as such:
#!/bin/bash
cat input-a input-b > /dev/null
LD_PRELOAD= problematic-command output-tmp
cat output-tmp > actual-output
And in the .mk
file:
actual-output:
script.sh