#! /bin/sh set -euf ## SYNOPSIS # [debug=true] build compile SRCFILE DSTFILE # [debug=true] build deps SRCFILE... build() { case "$1" in compile) build_compile "$2" "$3";; deps) shift; build_deps "$@";; *) echo "build: $1: bad command" >&2; return 23;; esac } ## usage: #@include \([0-9A-Za-z]\+\) -> build_include \1 \2 build_include() { cat< build_info \1 build_info() { cat< "$2" chmod +x "$2" } ## usage: needs_compilation SHELLSCRIPT SENTINEL # Returns true if SRCFILE contains compilation directives. needs_compilation() { echo "$1" | grep -q "$2" } ## usage: make_sedscript_maker_shellscript SRCFILE INPUT_PARSER # Print a shellscript that creates a sedscript that resolves all the build # directives in SRCFILE. make_sedscript_maker_shellscript() { defvar sedscript_generator "$(echo "$1" | nl -b a -s ' ' | sed "$2")" \ 'sed input_parser srcfile' defvar sedscript "$(eval "$sedscript_generator")" 'eval sedscript_generator' echo "$sedscript" } ## usage: build_deps SRCFILE... # Print all the dependencies of SRCFILE... (in alphabetic order) to stdout. build_deps() { while test $# -gt 0; do deps="$( for f; do for d in $(sed -n 's:^'"$build_include_directive"'$:\1:p' "$f"); do build_resolve $d done done )" set -- $deps if test $# -gt 0; then echo "$deps" fi done | sort | uniq } ## usage: build_resolve LIBNAME build_resolve() { echo "$BUILD_PATH" | tr : \\n | xargs -I: printf '%s/%s\n' : "$1" | xargs -I: ls -d : 2>/dev/null | head -n 1 | grep . || { echo "build resolve: $1: library not found" >&2 return 23 } } ## usage: make_input_parser FILENAME make_input_parser() { echo "$(sed -n ' s/^## usage: \(.*\) -> \([^ ]\+\) \(.*\)$/s:^ *\\([0-9]\\+\\) \1$:\2 \3:/p $a\ t;s:^ *\\([0-9]\\+\\) .*:echo \\1p: ' "$1")" } ## usage: make_build_directives FILENAME make_build_directives() { echo "$(sed -n ' s/^## usage: \(.*\) -> \([^ ]\+\) \(.*\)$/\2_directive/p ' "$0")" } ## usage: make_build_x_directive_loader FILENAME make_build_x_directive_loader() { sed -n ' s/^## usage: \(.*\) -> \([^ ]\+\) \(.*\)$/\2_directive='"'"'\1'"'"'/p ' "$1" } ## usage: make_needs_compilation_sentinel BUILD_DIRECTIVES... make_needs_compilation_sentinel() { echo "^\\($( for directive; do eval echo \"\$$directive\" done | tr \\n \| | sed 's/|/\\|/' )\\)$" } ## usage: defvar NAME VALUE [DESCRIPTION] defvar() { eval "$1=\"\$2\"" if test "${debug-false}" = true; then printf '====== %s%s\n%s\n' \ "$1" \ "${3+" ($3)"}" \ "$(eval echo \"\$$1\" | nl -b a)" >&2 fi } ## main build "$@"