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