1 # depend.awk -- awk script used to construct makefile dependencies
2 # for nethack's source files (`make depend' support for Makefile.src).
3 # $NHDT-Date: 1546220373 2018/12/31 01:39:33 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.8 $
6 # cd src ; nawk -f depend.awk ../include/*.h list-of-.c/.cpp-files
8 # This awk program scans each file in sequence, looking for lines beginning
9 # with `#include "' and recording the name inside the quotes. For .h files,
10 # that's all it does. For each .c file, it writes out a make rule for the
11 # corresponding .o file; dependencies in nested header files are propagated
14 # config.h and hack.h get special handling because of their heavy use;
15 # timestamps for them allow make to avoid rechecking dates on
16 # subsidiary headers for every source file;
17 # extern.h gets special handling to avoid excessive recompilation
19 # patchlev.h gets special handling because it only exists on systems
20 # which consider filename patchlevel.h to be too long;
21 # interp.c gets special handling because it usually doesn't exist; it's
22 # assumed to be the last #include in the file where it occurs.
23 # win32api.h gets special handling because it only exists for some ports;
24 # it's assumed to be the last #include in the file where it occurs
27 BEGIN { FS = "\"" #for `#include "X"', $2 is X
28 special[++sp_cnt] = "../include/config.h"
29 special[++sp_cnt] = "../include/hack.h"
30 alt_deps["../include/extern.h"] = ""
31 alt_deps["../include/patchlev.h"] = ""
32 alt_deps["interp.c"] = " #interp.c" #comment it out
33 alt_deps["../include/win32api.h"] = " #../include/win32api.h"
34 alt_deps["../include/zlib.h"] = " #zlib.h" #comment it out
36 FNR == 1 { output_dep() #finish previous file
37 file = FILENAME #setup for current file
39 /^\#[ \t]*include[ \t]+\"/ { #find `#include "X"'
41 #[3.4.0: gnomehack headers currently aren't in include]
42 #[3.6.2: Qt4 headers aren't in include either]
43 #[3.6.2: curses headers likewise]
45 if (incl ~ "curses\.h")
46 incl = "" # skip "curses.h"; it should be <curses.h>
47 else if (incl ~ /^curs/) # curses special case
48 incl = "../win/curses/" incl
49 else if (incl ~ /^qt4/) # Qt v4 special case
50 incl = "../win/Qt4/" incl
51 else if (incl ~ /^gn/) # gnomehack special case
52 incl = "../win/gnome/" incl
54 incl = "../include/" incl
56 deps[file] = deps[file] " " incl
58 END { output_dep() } #finish the last file
62 # `file' has been fully scanned, so process it now; for .h files,
63 # don't do anything (we've just been collecting their dependencies);
64 # for .c files, output the `make' rule for corresponding .o file
66 function output_dep( targ)
68 if (file ~ /\.cp*$/) {
69 #prior to very first .c|.cpp file, handle some special header file cases
72 #construct object filename from source filename
73 targ = file; sub("^.+/", "", targ); sub("\\.cp*$", ".o", targ)
74 #format and write the collected dependencies
75 format_dep(targ, file)
80 # handle some targets (config.h, hack.h) via special timestamping rules
82 function output_specials( i, sp, alt_sp)
84 for (i = 1; i <= sp_cnt; i++) {
86 #change "../include/foo.h" first to "foo.h", then ultimately to "$(FOO_H)"
87 alt_sp = sp; sub("^.+/", "", alt_sp)
88 print "#", alt_sp, "timestamp" #output a `make' comment
89 #- sub("\\.", "_", alt_sp); alt_sp = "$(" toupper(alt_sp) ")"
90 #+ Some nawks don't have toupper(), so hardwire these instead.
91 sub("config.h", "$(CONFIG_H)", alt_sp); sub("hack.h", "$(HACK_H)", alt_sp)
92 format_dep(alt_sp, sp) #output the target
93 print "\ttouch " alt_sp #output a build command
94 alt_deps[sp] = alt_sp #alternate dependency for depend()
100 # write a target and its dependency list in pretty-printed format;
101 # if target's primary source file has a path prefix, also write build command
103 function format_dep(target, source, n, i, list)
105 split("", done) #``for (x in done) delete done[x]''
106 printf("%s:", target); col = length(target) + 1
107 #- printf("\t"); col += 8 - (col % 8);
108 #- if (col == 8) { printf("\t"); col += 8 }
109 source = depend("", source, 0)
110 n = split(source, list, " +")
111 for (i = 2; i <= n; i++) { #(leading whitespace yields empty 1st element)
112 if (col + length(list[i]) >= (i < n ? 78 : 80)) {
113 printf(" \\\n\t\t"); col = 16 #make a backslash+newline split
117 printf("%s", list[i]); col += length(list[i])
119 printf("\n") #terminate
120 #write build command if first source entry has non-include path prefix
122 if (source ~ /\// && substr(source, 1, 11) != "../include/") {
123 if (source ~ /\.cpp$/ )
124 print "\t$(CXX) $(CXXFLAGS) -c -o $@ " source
125 else if (source ~ /\/X11\//) # "../win/X11/foo.c"
126 print "\t$(CC) $(CFLAGS) $(X11CFLAGS) -c -o $@ " source
127 else if (source ~ /\/gnome\//) # "../win/gnome/foo.c"
128 print "\t$(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ " source
130 print "\t$(CC) $(CFLAGS) -c -o $@ " source
135 # recursively add the dependencies for file `name' to string `inout'
136 # (unless `skip', in which case we're only marking files as already done)
138 function depend(inout, name, skip, n, i, list)
141 if (name in alt_deps) { #some names have non-conventional dependencies
142 if (!skip) inout = inout " " alt_deps[name]
144 } else { #ordinary name
145 if (!skip) inout = inout " " name
148 #- n = split(deps[name], list, " +")
149 #- for (i = 2; i <= n; i++) #(leading whitespace yields empty 1st element)
150 #- inout = depend(inout, list[i], skip)
151 #+ At least one implementation of nawk handles the local array `list' wrong,
152 #+ so the clumsier substitute code below is used as a workaround.
153 list = deps[name]; sub("^ +", "", list)
155 match((list " "), " +"); i = RSTART; n = RLENGTH
156 inout = depend(inout, substr(list, 1, i-1), skip)
157 list = substr(list, i+n)