commit 08bea15

shrub  ·  2026-06-30 16:14:11 +0000 UTC
parent 1ec538a
add deps script
1 files changed,  +97, -0
A deps
A deps
+97, -0
 1@@ -0,0 +1,97 @@
 2+#!/bin/sh
 3+# emit makefile dependencies for a list of C sources using the compiler's .d output. having a bunch of 
 4+# autogenerated .d files and -include's is flaky and ugly, and might not work on all make 
 5+# implementations. this way you can generate the deps once and ship the makefile. 
 6+# it takes a list of files from stdin and prints to stdout. you might also want to append
 7+# you CFLAGS/CPPFLAGS if that will change the deps.
 8+#
 9+# example:
10+#     find . -type f -name '*.c' | CPPFLAGS='-Iinclude' deps >> Makefile
11+#
12+
13+set -eu
14+
15+cc=${CC:-cc}
16+cppflags=${CPPFLAGS:-}
17+cflags=${CFLAGS:-}
18+tmpbase=${TMPDIR:-/tmp}
19+
20+cleanup() {
21+	rm -rf "$tmpdir"
22+}
23+
24+usage() {
25+	printf 'usage: %s [file.c ...]\n' "${0##*/}" >&2
26+	printf '       %s < file-list\n' "${0##*/}" >&2
27+	exit 2
28+}
29+
30+list() {
31+	if [ "$#" -gt 0 ]; then
32+		for src do
33+			case $src in
34+			*.c) printf '%s\n' "$src" ;;
35+			*) printf '%s: not a .c file: %s\n' "${0##*/}" "$src" >&2; exit 2 ;;
36+			esac
37+		done
38+		return
39+	fi
40+
41+	while IFS= read -r src; do
42+		[ -n "$src" ] || continue
43+		case $src in
44+		*.c) printf '%s\n' "$src" ;;
45+		*) printf '%s: not a .c file: %s\n' "${0##*/}" "$src" >&2; exit 2 ;;
46+		esac
47+	done
48+}
49+
50+if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then
51+	usage
52+fi
53+
54+tmpdir=$(mktemp -d "$tmpbase/deps.XXXXXX")
55+trap cleanup EXIT HUP INT TERM
56+
57+count=0
58+srcs=$tmpdir/sources
59+list "$@" > "$srcs"
60+
61+if [ ! -s "$srcs" ]; then
62+	printf '%s: no .c files provided\n' "${0##*/}" >&2
63+	exit 1
64+fi
65+
66+printf '\n'
67+printf '#AUTOGENERATED\n'
68+
69+while IFS= read -r src; do
70+	dep=$tmpdir/$count.d
71+	obj=${src%.c}.o
72+	"$cc" $cppflags $cflags -MMD -MF "$dep" -MT "$obj" -E -o /dev/null "$src"
73+	#flatten the block with one target: dep line per prereq
74+	awk '
75+	BEGIN {
76+		rule = ""
77+	}
78+	{
79+		line = $0
80+		sub(/\\$/, "", line)
81+		rule = rule line " "
82+		if ($0 !~ /\\$/) {
83+			sub(/^[[:space:]]*/, "", rule)
84+			split(rule, parts, ":")
85+			target = parts[1]
86+			deps = substr(rule, length(target) + 2)
87+			n = split(deps, items, /[[:space:]]+/)
88+			for (i = 1; i <= n; ++i) {
89+				if (items[i] == "")
90+					continue
91+				print target ": " items[i]
92+			}
93+			rule = ""
94+		}
95+	}
96+	' "$dep"
97+	count=$((count + 1))
98+done < "$srcs"