commit 23b7ad133bdb262106b265ca87f252b6bf812abb from: Benjamin Stürz date: Sat Mar 02 01:22:31 2024 UTC initial commit commit - /dev/null commit + 23b7ad133bdb262106b265ca87f252b6bf812abb blob - /dev/null blob + 62e0d949b816082fc0d86f486f63a3b5fddb74de (mode 644) Binary files /dev/null and .make.awk.swp differ blob - /dev/null blob + 38e0700e0b24c4bf13936f27cd9bef79fdde5b47 (mode 644) --- /dev/null +++ Makefile @@ -0,0 +1,16 @@ +.POSIX: + +PREFIX = /usr/local + +all: make + +clean: + rm -f make + +install: make + mkdir -p ${DESTDIR}${PREFIX}/bin + cp -f make ${DESTDIR}${PREFIX}/bin/ + +make: make.awk + (printf "#!/bin/sh\ncode=%c\n" \'; cat make.awk; printf '%c\nawk -v args="$$*" "$$code" Makefile\n' \') > $@ + chmod +x $@ blob - /dev/null blob + dc9f14a18c2d872ae9a5631634bf40e1ac051faf (mode 644) --- /dev/null +++ make.awk @@ -0,0 +1,189 @@ +# awkward make + +function strip(s) { + sub(/^[[:space:]]*/, "", s); + sub(/[[:space:]]*$/, "", s); + return s; +} + +function find(name) { + for (i = 1; i <= length(data);) { + if (data[i] == name) + return i; + i += data[++i] + 1; + i += data[i] + 1; + } + return 0; +} + +function isnewer(a, b) { + cmd = sprintf("ls -1t '%s' '%s' 2>&1", a, b); + cmd | getline file; + close(cmd); + regex = "^" a "\*?$"; + return file ~ regex; +} + +function exists(f) { + cmd = sprintf("ls '%s' > /dev/null 2>&1", f); + return system(cmd) == 0; +} + +function expand(s, rulename, i, out, name, ch, chars) { + out = ""; + split(s, chars, ""); + for (i = 1; i <= length(chars);) { + ch = chars[i++]; + if (ch != "$") { + out = out ch; + continue; + } + + ch = chars[i++]; + + if (ch == "{") { + name = ""; + while (1) { + ch = chars[i++]; + if (ch == "}") + break; + name = name ch; + } + + out = out macros[name]; + } else if (ch == "$") { + out = out "$"; + } else if (ch == "@") { + out = out rulename; + } else { + print "ERROR: invalid replacement"; + exit 1; + } + } + return out; +} + +function run(pos, name, updated, num, i, dep, cmd) { + name = data[pos]; + num = data[++pos]; + ++pos; + + updated = !exists(name); + + for (i = 1; i <= num; ++i) { + dep = data[pos++]; + rule = find(dep); + + if (exists(dep)) { + if (isnewer(dep, name)) + updated = 1; + } + + if (rule != 0) { + if (run(rule)) + updated = 1; + } else if (!exists(dep)) { + print "ERROR: No rule for", dep; + exit 1; + } + } + + if (updated == 0) + return 0; + + num = data[pos++]; + for (i = 1; i <= num; ++i) { + cmd = data[pos++]; + print cmd; + cmd = expand(cmd, name); + if (system(cmd) != 0) { + print "ERROR: Command failed"; + exit 1; + } + } + return 1; +} + +BEGIN { + pos = 1; + saved = -1; +} + +# Empty lines and comments +/^[[:space:]]*(#.*)?$/ { next; } + +# Macro Definitions +/^[a-zA-Z_][a-zA-Z_0-9]*[[:space:]]*=.*$/ { + split($0, x, "="); + macros[strip(x[1])] = strip(x[2]); + next; +} + +# Rule Declarations +/^[^:]+:[^:]*$/ { + split($0, x, ":"); + split(strip(x[1]), targets, "[[:space:]]+"); + if (length(targets) != 1) { + print "ERROR: no multi-targets supported"; + exit 1; + } + target = targets[1]; + split(strip(x[2]), deps, "[[:space:]]+"); + + if (target ~ /^\..*$/) { + if (target == ".POSIX") + next; + print "ERROR: invalid directive" target; + exit 1; + } + + data[pos++] = target; + data[pos++] = length(deps); + for (i = 1; i <= length(deps); ++i) { + data[pos++] = deps[i]; + } + saved = pos++; + data[saved] = 0; + next; +} + +# Rule Commands +/^\t.*$/ { + if (saved == -1) { + print "ERROR: no rule declaration"; + exit 1; + } + gsub(/^\t/, ""); + data[saved]++; + data[pos++] = $0; +} + +END { + split(args, argv, "[[:space:]]+"); + + k = 1; + + for (i = 1; i <= length(argv); ++i) { + arg = argv[i]; + if (arg ~ /^[^=]+=.*$/) { + split(arg, m, "="); + macros[m[1]] = m[2]; + } else { + rules[k++] = arg; + } + } + + if (length(rules) != 0) { + for (k = 1; k <= length(rules); ++k) { + name = rules[k]; + rule = find(name); + if (rule == 0) { + print "No such rule:", name; + exit 1; + } + run(rule); + } + } else { + run(1); + } +}