shake

minimal build system that generates Ninja build files

git clone https://9o.is/git/shake.git

commit 79f83c96550ce40f2cb975a71fc441504acb28f9
parent 6037e5a59dd80820ff649e5adca0cc694a810d83
Author: Jul <jul@9o.is>
Date:   Sun, 15 Mar 2026 23:33:06 +0800

add groupin/groupout functions

Diffstat:
MREADME.md | 18++++++++++++++++++
Mshake | 55+++++++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 65 insertions(+), 8 deletions(-)

diff --git a/README.md b/README.md @@ -216,6 +216,24 @@ Include shared definitions with `import`: import rules.sh ``` +### Grouping build inputs and outputs + +Build inputs and outputs are tracked by shake. You can group inputs or outputs +using an extended regular expression pattern to create a phony target. + +For example, the following creates a phony headers target and groups all generated header files: + +```sh +groupout headers '.*\.h$' +``` + +If you need to fetch source files and extract them into `src/` subdirectory before +compiling, the following groups all src files to depend on the phony fetch target: + +```sh +groupin fetch '\$dir/src/.*' +``` + ## Examples See the `example/` directory for working examples: diff --git a/shake b/shake @@ -83,24 +83,55 @@ _shake_open() { _shake_close() { _f=$SHAKEFILE - gen $_f.ninja $_f.ins $_f.out: - $GEN_FILES - phony ninja: $NINJA_FILES - - exec 3>&- exec 4>&- exec 5>&- + wait + + if [ ! "$TARGET" ] || [ $TARGET = "$DIR" ]; then + sort -u $_f.ins.tmp -o $_f.ins + sort -u $_f.out.tmp -o $_f.out + rm -f $_f.ins.tmp + rm -f $_f.out.tmp + + if [ "${SHAKE_GROUPIN-}" ]; then + set -- $SHAKE_GROUPIN + while [ "${1-}" ] && [ "${2-}" ]; do + if grep -E "$2" $_f.ins 2>/dev/null >$SHAKEDIR/$1.ins; then + printf 'build ' >&3 + cat $SHAKEDIR/$1.ins | tr '\n' ' ' >&3 + printf ': phony $dir/%s\n' "$1" >&3 + fi + shift 2 + done + unset -v SHAKE_GROUPIN + fi + + if [ "${SHAKE_GROUPOUT-}" ]; then + set -- $SHAKE_GROUPOUT + while [ "${1-}" ] && [ "${2-}" ]; do + if grep -E "$2" $_f.out 2>/dev/null >$SHAKEDIR/$1.out; then + printf 'build $dir/%s: phony ' "$1" >&3 + cat $SHAKEDIR/$1.out | tr '\n' ' ' >&3 + printf '\n' >&3 + fi + shift 2 + done + unset -v SHAKE_GROUPOUT + fi + printf 'build %s: gen | %s\n' "$_f.ninja $_f.ins $_f.out" "$GEN_FILES" >&3 + printf 'build $dir/ninja: phony %s\n' "$NINJA_FILES" >&3 + fi + + exec 3>&- wait + if [ ! "$TARGET" ] || [ $TARGET = "$DIR" ]; then if cmp -s $_f.ninja.tmp $_f.ninja; then rm -f $_f.ninja.tmp else mv $_f.ninja.tmp $_f.ninja fi - sort -u $_f.ins.tmp -o $_f.ins - sort -u $_f.out.tmp -o $_f.out - rm -f $_f.ins.tmp - rm -f $_f.out.tmp fi } @@ -228,6 +259,14 @@ phony() { build phony $* } +groupin() { + SHAKE_GROUPIN="${SHAKE_GROUPIN-} $1 $2" +} + +groupout() { + SHAKE_GROUPOUT="${SHAKE_GROUPOUT-} $1 $2" +} + error() { printf "shake: %s: %s\n" "$DIR" "$*" >&2 exit 1