posix-build
===========
Overview
--------
Have you ever said "if only this was sh, it would be easy", while using make
(even less portable ones like GNU make)? Have you tried to extend it beyond
basic use while fighting its warts?
I have, and that's why I've come up with a collection of (mostly) POSIX sh
functions to wrap around POSIX make (which is used as intended: a recipe
processor).
Here are some of its features:
* Proper install/uninstall without needing install(1) to normalize PREFIX.
* Simple runtime path rewriting for sh(1) scripts, allowing for inplace and
installed use alike.
* A compiler flag detector (autoconf like features left as exercise to those
who need it).
* With the aforementioned detector, easy handling of LTO and PGO for both
gcc and clang.
* Some default compilation variables like NATIVE and STATIC or flag presets
in the form of CONFIG.
* gperf and lex files handling (note: a `file.lex` or `file.gperf` is
expected to produce a `file.c`, because SUFFIX rules don't allow for
`file.lex.c`).
* No macro/environment mess like make, only use the environment since it's
a nice builtin associative array that is automatically passed to
subprocesses.
* Since it's sh, it's as extensible as your sh writing skills, no need to
bolt so much on make, and with a different syntax to boot.
* Compilation database can be handled by the following external script:
https://git.sr.ht/~q3cpma/scripts/tree/master/item/mkcdb
Note that since this uses make, it inherits its awful lack of whitespace
handling. Also note that this project is really C oriented, use with C++ and
other programming languages would probably need some work.
Dependencies
------------
* A POSIX environment, obviously
* sed -E (GNU, *BSD, MacOS, Illumos; POSIX-2024)
* realpath (GNU, *BSD, MacOS >= 13; POSIX-2024)
* mktemp -d (GNU, *BSD, MacOS, Illumos)
* local/typeset in sh (all except AT&T ksh)
Command line description
------------------------
A typical use (build then install) using bmake with 4 jobs:
$ CC=c99 MAKE=bmake JOBS=4 LTO=false PGO=false NATIVE=false STATIC=false \
USE_FEATURE1=true USE_FEATURE2=false ./build.sh
# PREFIX=/opt ./build.sh install
Here's the more detailed usage message:
+----------------------------------------------------------------------------------+
| SYNOPSIS |
| build.sh [ACTION] |
| PGO=true build.sh CMD [ARGS] |
| |
| DESCRIPTION |
| Build script getting its configuration from the environment and accepting |
| the following ACTIONs: |
| * clean |
| * install |
| * uninstall |
| * help |
| |
| When no ACTION is given, the program is built. |
| When PGO is selected through the environment, CMD [ARGS] is run to profile |
| the program before rebuilding. |
| |
| This notice is generic, read the README for possibly more. |
| |
| ENVIRONMENT |
| CC |
| C compiler to use. Defaults to c99(1p). |
| |
| LD |
| Linker passed to CC via -fuse-ld (if available). |
| |
| CFLAGS |
| Additional flags passed to CC when compiling sources files into |
| objects. |
| |
| LDFLAGS |
| Additional flags passed to CC when linking the objects into the final |
| executable. |
| |
| PREFIX and DESTDIR |
| The program and its files are installed into or uninstalled from |
| "$DESTDIR$PREFIX/". PREFIX defaults to "/usr/local" and DESTDIR to |
| empty. |
| |
| MAKE |
| Executable to use as make(1p). Defaults to "make". |
| |
| JOBS |
| If some steps in the compilation support parallel processing, choose |
| the number of parallel jobs to run. Defaults to 1. |
| |
| LTO |
| Try to use link-time optimization when value is "true". Defaults to |
| "false". |
| |
| PGO |
| Try to use profile-guided optimization using the arguments as a command |
| to run to profile the program when value is "true". Defaults to "false". |
| |
| STATIC |
| Try to link statically when value is "true". Defaults to "false". |
| |
| NATIVE |
| Try to enable optimizations specific to the host CPU when value is |
| "true". Defaults to "false". |
| |
| CONFIG |
| Choose a flag preset corresponding to a build type. Available values |
| are "release", "debug" and "profile". Defaults to "release". |
| |
+----------------------------------------------------------------------------------+
Example description
-------------------
This repo is given as an example, build.sh and prog-c/build.sh should be
inspected and modified before copy-pasting them. Only build_util.sh should be
kept untouched.
The example is a project containing a sh script and a subproject with a C
program called by the script.
This configuration shows most of the functionalities available.
Here's what the installation looks like after installing:
$ LTO=true CC=gcc ./build.sh
gcc -O3 -std=c99 -pedantic -Wall -Wextra -flto -fno-fat-lto-objects -D_DEFAULT_SOURCE -DPROG_NAME="\"prog-c\"" -DPROG_VERSION="\"fa5eb349c3fcbb295b664256f6e792b55051fdfa\"" -DNDEBUG -DUSE_FEATURE1 -o prog-c.o -c prog-c.c
gcc -O3 -std=c99 -pedantic -Wall -Wextra -flto -fno-fat-lto-objects -D_DEFAULT_SOURCE -DPROG_NAME="\"prog-c\"" -DPROG_VERSION="\"fa5eb349c3fcbb295b664256f6e792b55051fdfa\"" -DNDEBUG -DUSE_FEATURE1 -o feature1.o -c feature1.c
gcc -s -Wl,-O1 -Wl,-z,defs -flto=1 -O3 -std=c99 -pedantic -Wall -Wextra prog-c.o feature1.o -o prog-c -pthread -lm
$ PREFIX=prefix ./build.sh install
Installing prog into /home/user/Programming/posix-build/prefix/bin/prog
Installing util.sh into /home/user/Programming/posix-build/prefix/share/example-project/util.sh
Installing README into /home/user/Programming/posix-build/prefix/share/doc/example-project/README
Installing prog-c into /home/user/Programming/posix-build/prefix/bin/prog-c
Installing README to /home/user/Programming/posix-build/prefix/share/doc/example-project/README_prog-c
$ tree prefix
prefix
├── bin
│ ├── prog
│ └── prog-c
└── share
├── doc
│ └── example-project
│ ├── README
│ └── README_prog-c
└── example-project
└── util.sh
$ prefix/bin/prog hello world
prog-c 40d2902b89fa6e5340798d13201842f851041537
Feature1 enabled, feature1 value: 1
hello
world
Here's my source code:
...
To do
-----
* Add lint action (clang-analyze/scan-build, cppcheck, frama-c, blast, infer)
* Integrate optional features so that the build system always knows the full source list