- Shell 92.6%
- Makefile 7.4%
|
Baptiste Daroussin
bae2494e4a
Add install.sh for bootstrapping new projects
Usage: git clone bbuild; cd myproject; ../bbuild/install.sh |
||
|---|---|---|
| examples | Update example configure.def with universal patterns | |
| mk | Add PACKAGE_NAME, VERSION and datadir to mk/defs.mk.in | |
| tests | Add tests for PACKAGE_NAME, VERSION and datadir in defs.mk | |
| configure | Fix pkgconfigdir default bug | |
| install.sh | Add install.sh for bootstrapping new projects | |
| LICENSE | initial commit | |
| README.md | Document PACKAGE_NAME, VERSION and datadir in README | |
bbuild
A lightweight, portable build configuration system for C projects. Pure POSIX shell -- no external dependencies beyond a C compiler and standard Unix utilities:
- mktemp
- rm
- sed
- awk
- mv
- mkdir
- dirname
- tr
- uname
bbuild inspired by autosetup with a
single configure script and a set of reusable Makefile fragments (mk/).
Build configuration is declared in an configure.def file using simple shell
function calls.
Quick start
Copy into your project:
your-project/
configure <- from bbuild
config.guess <- optional, from GNU (for accurate host detection)
configure.def <- you write this
mk/
common.mk <- from bbuild
defs.mk.in <- from bbuild (customize if needed)
prog.mk <- from bbuild (if building executables)
static-lib.mk <- from bbuild (if building static libraries)
lib.mk <- from bbuild (if building shared + static libraries)
dir.mk <- from bbuild (if using recursive make)
Makefile.in <- you write this
src/
...
Then users run the familiar:
./configure --prefix=/usr/local
make
make install
Writing configure.def
configure.def is a POSIX shell script sourced by configure. It uses
declarative-style function calls to describe the project's requirements.
Minimal example
use cc
define VERSION 1.0.0
options \
"with-debug => enable debug build"
_configure_apply
cc_check_functions strlcpy
make_config_header config.h -auto VERSION
make_template mk/defs.mk.in
make_template Makefile.in
Skeleton with common patterns
use cc cc-lib pkg-config
define VERSION 0.1.0
options \
"with-asan => build with AddressSanitizer" \
"with-ubsan => build with UndefinedBehaviorSanitizer" \
"enable-tests=1 => build and run tests (default: enabled)"
_configure_apply
cc_check_tools ar ranlib strip
# Required library via pkg-config
if ! pkg_config_init; then
user_error "pkg-config is required"
fi
if ! pkg_config sqlite3; then
user_error "sqlite3 is required"
fi
# Optional library
if pkg_config libfoo; then
define HAS_FOO 1
fi
# Check functions
cc_check_functions strlcpy arc4random getprogname
# Check with specific link flags
cc_with "-libs -lm" cc_check_functions ceil
# Sanitizers
if opt_bool with-asan; then
define_append ASAN_CFLAGS -O0 -g -fsanitize=address
define_append ASAN_LDFLAGS -fsanitize=address
define asan 1
fi
make_config_header config.h -auto VERSION
make_template mk/defs.mk.in
make_template Makefile.in
API Reference
Variables
| Function | Description |
|---|---|
define KEY VALUE |
Set a variable |
define_append KEY VALUE |
Append to existing variable (space-separated) |
undefine KEY |
Remove a variable |
get_define KEY |
Print the value of a variable (for use in $(...)) |
is_defined KEY |
Return true if the variable exists |
is_true KEY |
Return true if defined and not "" or "0" |
define_feature NAME [0|1] |
Define HAVE_NAME (uppercased, - becomes _) |
Options
| Function | Description |
|---|---|
options SPEC... |
Declare project options |
opt_bool NAME |
Return true if boolean option is enabled |
opt_str NAME |
Print value of string option; return true if set |
_configure_apply |
Must be called after options() to process --flags |
Option spec format: "name[=default\|:default] => description"
with-*options generate--with-NAME/--without-NAMEflagsenable-*options generate--enable-NAME/--disable-NAMEflagsname:defaultdefines a string option with a default value
Compiler checks
| Function | Description |
|---|---|
cc_check_functions FUNC... |
Check for C functions. Defines HAVE_FUNC |
have_func FUNC |
Return true if function was found |
cc_check_includes HDR... |
Check for headers. Defines HAVE_HDR |
cc_check_members MEMBER... |
Check struct members (e.g. "struct stat.st_mtim") |
cc_check_decls DECL... |
Check symbol declarations. Defines HAVE_DECL_X |
cc_check_types TYPE... |
Check for types. Defines HAVE_TYPE |
cc_check_tools TOOL... |
Check for tools (ar, ranlib, etc.) |
cc_check_progs PROG... |
Check for programs. Returns 0 if found |
cc_path_progs PROG... |
Like above, but defines PROG=/path/to/prog |
cctest CODE |
Compile+link arbitrary C code. Returns 0 on success |
cc_with SPEC COMMAND ARGS... |
Run command with temporary flags |
cc_with spec format: -libs -lfoo -includes header.h -cflags -DFOO
pkg-config
| Function | Description |
|---|---|
pkg_config_init |
Check for pkg-config/pkgconf. Call once before pkg_config |
pkg_config SPEC |
Query a package. Defines PKG_NAME_{CFLAGS,LDFLAGS,LIBS} |
pkg_config accepts version constraints: pkg_config "libfoo >= 2.0"
Output
| Function | Description |
|---|---|
msg TEXT |
Print a message |
msg_checking TEXT |
Print without newline (for check start) |
msg_result TEXT |
Print with newline (for check result) |
user_error TEXT |
Print error and exit |
user_notice TEXT |
Print a notice |
Generation
| Function | Description |
|---|---|
make_config_header FILE [-auto PAT...] [-bare PAT...] |
Generate C #define header |
make_template INPUT [OUTPUT] |
Process template with @VAR@ substitution |
make_config_header behavior:
HAVE_*defines are always emitted-auto PAT: emit matching keys (0 =#undef, integers bare, strings quoted)-bare PAT: emit matching keys with values unquoted (useful for enum-like defines)
If OUTPUT is omitted, make_template strips .in or .bb suffix.
Standard variables
These are predefined by configure:
| Variable | Value |
|---|---|
CC |
C compiler (auto-detected or from CC=...) |
host |
Host triplet (e.g. x86_64-unknown-freebsd14.0) |
prefix |
Installation prefix (default /usr/local) |
bindir, sbindir, mandir, datadir, sysconfdir |
Derived from prefix |
PACKAGE_NAME |
Project name (defined in configure.def via define PACKAGE_NAME) |
VERSION |
Project version (defined in configure.def via define VERSION) |
AR, RANLIB |
Archiver and ranlib tools (set by cc_check_tools) |
abs_top_srcdir |
Absolute path to source directory |
abs_top_builddir |
Absolute path to build directory |
SHOBJ_CFLAGS |
Flags for position-independent code (-fPIC) |
SH_LDFLAGS |
Shared library linker flags (-shared) |
SH_SOEXT |
Shared library extension (.so or .dylib) |
SH_SOPREFIX |
Soname flag prefix |
SH_SOEXTVER |
Versioned extension format (.so.%s) |
Host detection and config.guess
configure automatically detects the host triplet (e.g.
x86_64-unknown-freebsd14.0, aarch64-unknown-linux6.1). It first
looks for a [config.guess](https://savannah.gnu.org/projects/config) script
in the project root; if not found, it falls back to constructing a triplet
from uname.
If your project needs accurate host identification (e.g. to distinguish
FreeBSD from Linux for platform-specific code), you can ship a copy of
GNU config.guess in your project root. This is particularly useful
for cross-compilation scenarios.
The host triplet is available in configure.def via get_define host and is
commonly used with case for platform-specific logic:
_host=$(get_define host)
case "$_host" in
*-freebsd*)
define_feature capsicum
;;
*-linux*)
cc_with "-libs -lbsd" cc_check_functions getprogname
;;
*-darwin*)
define MACOS 1
;;
esac
Template syntax
Template files (.in) support two features:
Variable substitution
@VAR@ is replaced with the value of VAR from the define store.
CC= @CC@
PREFIX= @prefix@
Conditional blocks
@if asan
CFLAGS+= @ASAN_CFLAGS@
@endif
@if FEATURE
enabled=yes
@else
enabled=no
@endif
A variable is considered true if it is defined and not "" or "0".
Conditionals can be nested.
Makefile fragments (mk/)
mk/defs.mk.in
Template for build variables. Processed by make_template mk/defs.mk.in
to produce mk/defs.mk. Every other Makefile includes it:
include @builddir@/mk/defs.mk
The template includes PACKAGE_NAME, VERSION, CC, AR, RANLIB,
SHOBJ_CFLAGS, SH_LDFLAGS, LIBSOEXT, SH_SOEXT, SH_PREFIX,
PREFIX, top_srcdir, top_builddir, etcdir, libdir, bindir,
sbindir, includedir, mandir, datadir, sysconfdir, and pkgconfigdir.
Projects with additional variables (e.g. textlibdir) can extend or
customize this template in their own copy. The standard template also
provides conditional @if blocks for asan, lsan, ubsan, tsan,
and coverage, and includes all:, clean:, install:, check:,
and distclean: targets.
mk/common.mk
Shared compilation rules. Provides .c.o and .c.pico (PIC) suffix
rules with automatic dependency tracking.
mk/prog.mk
Build a single executable. Set PROG and SRCS:
include @builddir@/mk/defs.mk
PROG= myapp
SRCS= main.c utils.c
LOCAL_CFLAGS= -I$(top_srcdir)/include
LDFLAGS+= -lm
include $(MK)/prog.mk
mk/static-lib.mk
Build static libraries (lib$(LIB).a and lib$(LIB)_pic.a):
include @builddir@/mk/defs.mk
LIB= mylib
SRCS= foo.c bar.c
include $(MK)/static-lib.mk
mk/lib.mk
Build shared + static libraries:
include @builddir@/mk/defs.mk
LIB= mylib
SRCS= foo.c bar.c
include $(MK)/lib.mk
Produces lib$(LIB)$(LIBSOEXT), lib$(LIB)$(SH_SOEXT) (symlink), and
lib$(LIB).a.
mk/dir.mk
Recursive make into subdirectories:
include @builddir@/mk/defs.mk
DIRS= src lib tests
include $(MK)/dir.mk
Running the tests
sh tests/run_tests.sh
License
ISC