1 | # a demo is a name that can be make'd into an a.out,
|
---|
2 | # that designates a collection of compile units,
|
---|
3 | # each with a corresponding .src.c + .o file pair
|
---|
4 | SOURCES_IN_DEMO=$(wildcard $1/*.src.c)
|
---|
5 | OBJECTS_IN_DEMO=$(patsubst %.src.c,%.o,$(call SOURCES_IN_DEMO,$1))
|
---|
6 | ALL_OBJECTS=$(foreach demo,$(DEMOS),$(call OBJECTS_IN_DEMO,$(demo)))
|
---|
7 |
|
---|
8 | # each recursive subdir gives a demo
|
---|
9 | # a demo name may have slashes in middle, but not at start or end (foo, foo/bar)
|
---|
10 | DIRS_REC=$(shell find ./* -type d)
|
---|
11 | DEMOS_FROM_DIRS=$(patsubst ./%,%,$1)
|
---|
12 | DEMO_OF_FILE=$(patsubst %/,%,$(dir $1))
|
---|
13 | DEMOS=$(call DEMOS_FROM_DIRS,$(DIRS_REC))
|
---|
14 |
|
---|
15 | # demos of working code build under target `all`
|
---|
16 | # default assumption = demo is working
|
---|
17 | # demos named err-% recursively opt out
|
---|
18 | ERR_DIRPATS=err-%
|
---|
19 | DEMOS_NONERR=$(filter-out $(ERR_DIRPATS),$(DEMOS))
|
---|
20 | DEMO_EXECS_NONERR=$(DEMOS_NONERR:=/a.out)
|
---|
21 |
|
---|
22 | # a recourse is a designated sub-demo of an error case
|
---|
23 | # that is expected to build successfully
|
---|
24 | RECOURSE_DIRPATS=%/recourse-classic
|
---|
25 | DEMOS_RECOURSE=$(filter $(RECOURSE_DIRPATS),$(DEMOS))
|
---|
26 | DEMO_EXECS_RECOURSE=$(DEMOS_RECOURSE:=/a.out)
|
---|
27 |
|
---|
28 | # non-err and recourse demos try to build by default
|
---|
29 | ALL=$(DEMO_EXECS_NONERR) $(DEMO_EXECS_RECOURSE)
|
---|
30 |
|
---|
31 | # a shred is a *.c or *.h file generated from a *.src.c
|
---|
32 | SHRED_EXTS=.impl.c .defn.h .tdcl.h
|
---|
33 | SHREDS_OF_FILE=$(foreach st,$(SHRED_EXTS),$(1:=$(st)))
|
---|
34 | SHREDS_IN_DEMO=$(foreach src,$(call SOURCES_IN_DEMO,$1),$(call SHREDS_OF_FILE,$(src:.src.c=)))
|
---|
35 | SHREDS_IN_DEMO_OF_FILE=$(call SHREDS_IN_DEMO,$(call DEMO_OF_FILE,$1))
|
---|
36 |
|
---|
37 | # a 'classic' demo builds without shredding
|
---|
38 | CLASSIC_DIRPATS=%-classic
|
---|
39 | DEMOS_CLASSIC=$(filter $(CLASSIC_DIRPATS),$(DEMOS))
|
---|
40 | DEMOS_NONSHRED=$(DEMOS_CLASSIC)
|
---|
41 | OBJECTS_NONSHRED=$(foreach demo,$(DEMOS_NONSHRED),$(call OBJECTS_IN_DEMO,$(demo)))
|
---|
42 |
|
---|
43 | # everything else builds via shredding
|
---|
44 | DEMOS_SHRED=$(filter-out $(RECOURSE_DIRPATS),$(DEMOS))
|
---|
45 | OBJECTS_SHRED=$(foreach demo,$(DEMOS_SHRED),$(call OBJECTS_IN_DEMO,$(demo)))
|
---|
46 | ALL_SHREDS=$(foreach demo,$(DEMOS),$(call SHREDS_IN_DEMO,$(demo)))
|
---|
47 |
|
---|
48 |
|
---|
49 | CC=gcc
|
---|
50 | CPPP=./cfa-cppp
|
---|
51 | CQFLAGS=-Wall -Wextra -Werror
|
---|
52 |
|
---|
53 |
|
---|
54 | .SECONDEXPANSION: # enable dynamic prereqs from $$
|
---|
55 | .SUFFIXES: # disable traditional rules like make .o from .c by calling $(CC)
|
---|
56 |
|
---|
57 |
|
---|
58 | all: $(ALL)
|
---|
59 |
|
---|
60 | # troubleshooting, e.g. `make echo_DEMOS` runs `echo $(DEMOS)`
|
---|
61 | echo_% :
|
---|
62 | @echo '$($(@:echo_%=%))'
|
---|
63 |
|
---|
64 | #
|
---|
65 | # demo
|
---|
66 | #
|
---|
67 |
|
---|
68 | %/a.out : DEMO=$(@:/a.out=)
|
---|
69 | %/a.out : OBJECTS=$(call OBJECTS_IN_DEMO,$(DEMO))
|
---|
70 | %/a.out : $$(OBJECTS)
|
---|
71 | $(CC) $(OBJECTS) -o $@ $(CFLAGS) $(CQFLAGS)
|
---|
72 |
|
---|
73 | $(DEMOS) : $$@/a.out
|
---|
74 |
|
---|
75 | #
|
---|
76 | # object
|
---|
77 | #
|
---|
78 |
|
---|
79 | # object of regular, shredded, demo
|
---|
80 | # each CU depends on all other CUs' shreds
|
---|
81 | # conservative for rebuild (obviates -MMD), but helps do initial build
|
---|
82 | $(OBJECTS_SHRED) : CC_SRC=$(@:.o=.impl.c)
|
---|
83 | $(OBJECTS_SHRED) : SHREDS=$(call SHREDS_IN_DEMO_OF_FILE,$@)
|
---|
84 | $(OBJECTS_SHRED) : $$(SHREDS)
|
---|
85 |
|
---|
86 | # of nonshredded demo
|
---|
87 | $(OBJECTS_NONSHRED) : CC_SRC=$(@:.o=.src.c)
|
---|
88 | $(OBJECTS_NONSHRED) : CQFLAGS+= -MMD
|
---|
89 |
|
---|
90 | -include $(OBJECTS_NONSHRED:.o=.d)
|
---|
91 |
|
---|
92 | $(ALL_OBJECTS) :
|
---|
93 | $(CC) $(CC_SRC) -c -o $@ $(CFLAGS) $(CQFLAGS)
|
---|
94 |
|
---|
95 | #
|
---|
96 | # shred
|
---|
97 | #
|
---|
98 |
|
---|
99 | define SINGLE_SHREDEXT_RULE
|
---|
100 | %$1: %.src.c $(CPPP)
|
---|
101 | $(CPPP) $$@
|
---|
102 | endef
|
---|
103 |
|
---|
104 | $(foreach sfx,$(call SHREDS_OF_FILE,@),$(eval $(call SINGLE_SHREDEXT_RULE,$(sfx:@%=%))))
|
---|
105 |
|
---|
106 | #
|
---|
107 | # clean, misc
|
---|
108 | #
|
---|
109 |
|
---|
110 | # 2-line body is significant; \n ending 1st line is literal
|
---|
111 | define newline
|
---|
112 |
|
---|
113 |
|
---|
114 | endef
|
---|
115 |
|
---|
116 | CLEANPATS=$(call SHREDS_OF_FILE,*) *.o *.d a.out
|
---|
117 | clean:
|
---|
118 | $(foreach p,$(CLEANPATS),find . -name '$p' -type f -print -delete$(newline))
|
---|
119 |
|
---|
120 | .PRECIOUS: %.tdcl.h %.defn.h %.impl.c
|
---|
121 | .PHONY: all echo_% clean
|
---|