Collection of sh functions to make your own build system

39bf009 appendnl_new: fix

9 days ago

3515d41 pb_make: fix stdin swallowing

9 days ago


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

Here are some of its features:
    * Proper install/uninstall without needing install(1) nor readlink(1) -f 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
    * No macro/environment mess like make, only use the environment since it's
      a nice builtin associative array that is automatically passed to
    * 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.

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 need a lot of small edits.


* A POSIX environment, obviously
* mktemp(1) -d, only dependency I couldn't part with; it is available on GNU,
  FreeBSD, OpenBSD, NetBSD, DragonflyBSD, MacOS, Illumos and Tru64, though.
  mkdtemp(3) itself being POSIX and easy to use, a wrapper could be written in
  no time.
* A /bin/sh with local/typeset support (which is almost all of them).

        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
├── bin
│   ├── prog
│   └── prog-c
└── share
    ├── doc
    │   └── example-project
    │       ├── README
    │       └── README_prog-c
    └── example-project
        └── util.sh
$ prefix/bin/prog hello world
prog-c fa5eb349c3fcbb295b664256f6e792b55051fdfa
Feature1 enabled, feature1 value: 1

        To do

* Re(Add) profiling CONFIG for perf and for gprof
* Add lint action (clang-analyze/scan-build, cppcheck, frama-c, blast, infer)
* Separate sanitizers from CONFIG=debug and add clang's msan as option