Mincbuild, which stands for (Min)imalist (C) (Build)system, is a buildsystem designed to make project build easier for other minimalist C(++) software. Now, you may be worried that this is just like all the other buildsystems, and it has some shitty DSL that was designed by a group of crackheads rolling dice to decide on fundamental features, but no! The only piece of necessary configuration is a single conf file that describes the basics of how your project should be built.
Of course, with no buildsystem DSL, mincbuild is meaningfully more restrictive than other buildsystems. For example, you cannot build one set of files using one command, and another set of files using another command without setting up multiple configurations, but given that the target usage for mincbuild is other minimalist software which shouldn't really be doing this anyway, that's not really an issue.
As of writing this, mincbuild is only 1073 lines of C code, and the resulting binary from the build is 44KB in size.
If your software is so minimalist (or designed in such a way) that the entire source implementation fits in one file, you are better off using something like Make, because mincbuild (while it will also work for this use-case) is meant specifically for minimalist software implemented across multiple source files, allowing for incremental compilation.
First, clone the repository from the GitHub using:
Then, build the program. On Linux, this is a very simple process - mincbuild is designed for it. I have also had success with building mincbuild on Windows through MinGW, but it can be a trivial bit more involved.
To build on Linux, run:
To build on MinGW:
bootstrap.sh
in an editor (probably GNU nano)-lpthread
from LIBS
(MinGW may not support pthread)-DPRUNE_SINGLE_THREAD -DCOMPILE_SINGLE_THREAD
to CFLAGS
./bootstrap.sh
typedef unsigned short uint16;
. You can also add an
#include <sys/types.h>
higher up if needed, but it probably shouldn't be.CFLAGS="-std=c99 -pedantic -D_POSIX_C_SOURCE=200809 -D_GNU_SOURCE
-DPRUNE_SINGLE_THREAD -DCOMPILE_SINGLE_THREAD" ./mincbuild.exe
You will notice upon the mincbuild
binary that it prints build output with
an extremely simple progress bar. This is because I've personally always hated
it when buildsystems or build processes in general don't give you even a vague
indication of how long is left until completion.
As another note - something worth knowing is that the whole "PRUNE_SINGLE_THREAD COMPILE_SINGLE_THREAD" thing you do on MinGW will obviously neuter multithreaded functionality. This sucks for general usage, but is actually quite nice if you have specific compatibility requirements (I suppose MinGW actually counts as one?).
Anyway - now, you can install mincbuild to your system. To do this, run:
And if you ever want to remove mincbuild from your system, run:
First, to use mincbuild for a project, your project must follow a set, simple directory structure:
Obviously, the names of the files / directories involved can be changed,
they have just been named descriptively here for ease of understanding. The main
thing here is that this directory structure is set in stone. Technically you
can just use a single source directory for everything and mincbuild will allow
it, but by design, mincbuild is meant for the structure outlined above. The
rationale behind this is that it enforces a consistent project organization
which is common and easy to understand. Anyway, that part is fairly obvious and
requires no further elaboration - the interesting thing is the mincbuild.conf
.
The mincbuild conf takes the form of key = value
configuration pairs
(notice the significant whitespace between the key
, =
, and value
).
Comments begin with a #
, as with most basic conf files - and only lines which
begin with a #
(not including leading whitespace) will be treated as a
comment. If a #
comment appears at the end of an otherwise non-comment line,
it will not be treated as a comment.
To begin with, there are a few keys that are absolutely essential to the compilation phase of the build, and mincbuild will output an error if any of these are missing. See below:
cc
: Path to the compiler used for compilationcflags
: Flags passed to the compiler upon invocationsrc_dir
: Path to the project source directoryinc_dir
: Path to the project header directorylib_dir
: Path to the project build directory where compiled object files will
be placedproduce_output
: Boolean value determining whether linking should occur after
the compilation phase of the buildsrc_exts
: Space-separated list of all file extensions used for source files
within the projecthdr_exts
: Space-separated list of all file extensions used for header files
within the projectincs
: Space-separated list of all directories that should be added to the
include path besides the project include directory. Used for dependencies
stored on the project source treecc_inc_fmt
: Determines how include paths will be passed to the compiler upon
invocation. Should almost always be set to -I%i
cc_cmd_fmt
: Determines how the compiler will be invoked. Should almost always
be set to %c %f -o %c -c %s %i
cc_success_rc
: Return code outputted by the compiler upon a successful
compilation after being invoked. Should usually be set to 0
A basic mincbuild.conf
which contains all of these keys would look
something like this:
... which will define a C project with a src
source file directory, an
include
header file directory, and a lib
object file output directory.
Unlike src
and include
, lib
does not need to exist before the build
process - and will be automatically created if it is missing. When mincbuild is
invoked here, all source files in src
will be compiled to corresponding object
files in lib
, but the build will stop at that. No linking will occur and you
will be left with just compiled object files - which is useful in the
situation that you want to link them individually into other projects.
Oh, and, by the way, in case you haven't noticed - the dummy name NONE
is
used whenever a key should have an empty value, rather than just leaving it
blank. Another thing to keep in mind is that trailing significant whitespace
applies to the values of the configuration file: i.e. a value "hello" is
different to another value "hello " (notice the trailing space) but it is not
different to " hello" (notice the leading space). This is important to note
because if you meant to pass "NONE
" as one of the values, but accidentally
passed "NONE
" (with a trailing space), the behavior will not be the same in
both cases.
However, for most projects it won't be enough to simply compile all the
sources - you want to link them all together. In order to do this, you will need
to set produce_output
to true
and define the following keys, without which
the mincbuild linking phase cannot occur and an error will be outputted:
ld
: Path to the linker used for linkingldflags
: Flags passed to the linker upon invocationoutput
: Name of the output binary created upon linkinglibs
: Space-separated list of all libraries that should be linked into the
projectld_lib_fmt
: Determines how libraries will be passed to the linker upon
invocation. Should usually be set to -l%l
ld_obj_fmt
: Determines how object files will be passed to the linker upon
invocation. Should almost always be set to %o
ld_cmd_fmt
: Determines how the linker will be invoked. Should almost always
be set to %c %f -o %b %o %l
ld_success_rc
: Return code outputted by the linker upon a successful linking
after being invoked. Should usually be set to 0
A basic mincbuild.conf
which implements compilation and linking would look
something like:
... which will define a C project with all the same properties as before,
except mincbuild will now also link the compiled object files into an output
binary called demo
.
Finally, that's basically all you need to understand about the mincbuild
conf file and I can move on to the mincbuild
command line tool you built
during the previous part of this guide. Using the mincbuild
command line tool
is extremely simple. Just navigate to the project directory which contains the
mincbuild.conf
, and run:
Nice. Very simple. However, I said earlier that "the names of the files /
directories [in the project] can be changed", and this includes the mincbuild
conf. This is true, you can rename it to anything. If you rename
mincbuild.conf
to something else, say, buildinfo.conf
or something, you will
need to run the following command instead:
You may also pass some command line flags to mincbuild in the standard
getopt()
-compatible format in order to change certain parts of the build
process in such a way that a successful build won't differ in any way than a
clean mincbuild
invocation, but still provide some kind of useful
functionality. The possible flags are:
-r
: The pruning phase of the build will be skipped and all files will be
compiled. Even already built objects that don't strictly require rebuilding
will be recompiled. This is useful in two main cases: a) if you change the
mincbuild.conf
and want to rebuild the project with the new settings, and b)
if some part of your toolchain has changed in such a way that a full rebuild is
necessary-v
: Verbose output regarding the build process will be written to standard
output. The progress messages that are normally outputted will also contain the
commands invoked by mincbuild at that point in the buildAs well as the basic -h
flag that everyone already understands.
The fact that the compiler, linker, compiler flags, linker flags, etc. are hardcoded into the mincbuild conf is fine for most cases - especially if you've only tested your project on a single toolchain and cannot guarantee it building on anything else.
However, let's say you have a program with a conditional compilation path
which enables UTF-8 support for text handling, and to enable this conditional
compilation path, you must compile with -DENABLE_UTF_8_SUPPORT
. Well, it's
fine to make an edit to the conf file if you are an end user, but if you are a
programmer and need to frequently test your program both with and without
UTF-8, it certainly gets annoying to constantly make changes to a build file.
For this reason, mincbuild allows you to override specifically those variables. You can do this by setting the following environment variables:
CC
: compilerLD
: linkerCFLAGS
: compiler flagsLDFLAGS
: linker flagsSo, in our above example, you might do something like:
... to build with UTF-8 support.
If the environment variable is not set, mincbuild will simply use the value specified in the conf file.
As a hint, try running with -v
to see that the command has actually
changed after an override, and make sure it is correct. You should also remember
that compiling different parts of the same project with different flags is often
ill-advised.
In fact, to be completely safe, you might want to run this instead:
You now understand everything there is to know about the basics of using mincbuild.
This work by tirimid is licensed under CC BY-SA 4.0