09ecb8bc309abe5c9bba31812b7dfecc3743bcb9
[calc.git] / makefile
1 # Default flags
2
3 CC = gcc
4
5 #INCLUDES = -I../debug -D__MEMORY_ALLOCATION__
6 INCLUDES =
7 OFLAGS = -O4 -Os
8 #OFLAGS = -O0
9 #OFLAGS = -O4 -ffast-math -finline-functions
10 #OFLAGS = -O4 -finline-functions
11 #OFLAGS += -mtune=pentium3 -mmmx -msse -msse2 -m3dnow
12 #OFLAGS += -minline-all-stringops -fsingle-precision-constant
13 #OFLAGS += -malign-double
14 CFLAGS += -W -Wall -Wextra -g
15 #CFLAGS += -std=c99 -D_XOPEN_SOURCE=500
16 CFLAGS += $(OFLAGS) $(INCLUDES) $(OPTIONS)
17 LDFLAGS += -g $(LDOPTS) $(OPTIONS)
18
19 LDOPT = linker
20 MV = mv
21 ifneq (, $(findstring linux, $(MAKE_HOST)))
22 # Linux
23 else ifneq (, $(findstring mingw, $(MAKE_HOST)))
24 # Windows MinGw
25 CFLAGS += -DWIN32
26 #LDLIBS += -lws2_32
27 LDOPT = winlnk
28 else ifneq (, $(findstring cygwin, $(MAKE_HOST)))
29 CFLAGS += -DWIN32
30 # Windows CygWin
31 LDOPT = winlnk
32 else ifneq (, $(findstring msdos, $(MAKE_HOST)))
33 # MSDOS
34 LDOPT = doslnk
35 MV = move
36 endif
37
38 # Targets
39
40 ALLEXE = $(shell for f in *.c; do grep -q '/\*\slinker:' $$f && echo $${f/.c}; done)
41
42 SHELL = bash
43
44 #MAKE = mingw32-make
45 MAKEFLAGS += -s
46 include $(wildcard .makefile)
47
48 # Functions
49
50 TITLE = echo -en "\033[0;1m$(strip $(1))\033[0;0m:\t"
51 PASS = echo -e "\033[1;32m$(strip $(1))\033[0;0m"
52 WARN = echo -e "\033[1;33m$(strip $(1))\033[0;0m"
53 FAIL = echo -e "\033[1;31m$(strip $(1))\033[0;0m"
54
55 MKDIR = mkdir -p $(1) && chmod a+rx,go-w $(1)
56
57 INSTALL = test -d `dirname $(2)` || $(call MKDIR, `dirname $(2)`) && cp -pa $(1) $(2) && chmod a+rX,go-w $(2)
58
59 VALID = $(call TITLE, $(1)) && $(2) && $(call PASS, SUCCESS) || { $(call FAIL, FAILED); test; }
60
61 GETCOMMENTS = awk '/\/\*\s*$(1):/,/\*\// { sub(/.*\/\*\s*$(1):/, ""); sub (/\s*\*\/.*/, ""); print } /\/\/\s*$(1):/ {sub (/.*\/\/\s*$(1):/, ""); print }' $(2)
62 #GETCOMMENTS = perl -- getcomments.pl -p='$(1):\s' -f='%' $(2)
63
64 ## Generic rules
65
66 all: depends
67 $(MAKE) $(ALLEXE:%=%.exe)
68
69 analyze:
70 make purge
71 scan-build make
72 #scan-build -stats make
73
74 count:
75 wc $(wildcard *.c *.h) $(MAKEFILE_LIST)
76
77 clean:
78 $(call TITLE, "Cleaning")
79 touch clean
80 rm -f clean $(wildcard *.d *.ld *.log *.o *.test *~ .exec_* gmon.out _)
81 $(call PASS, SUCCESS)
82
83 depends: $(patsubst %.c, %.d, $(wildcard *.c)) $(patsubst %, %.ld, $(ALLEXE))
84
85 gcovs:
86 $(MAKE) $(addprefix gcov_,$(ALLEXE))
87
88 gprofs:
89 $(MAKE) $(addprefix gprof_,$(ALLEXE))
90
91 purge: clean
92 $(call TITLE, "Purging")
93 touch purge
94 rm -f purge $(ALLEXE:%=%.exe)
95 $(call PASS, SUCCESS)
96
97 valgrinds:
98 $(MAKE) all
99 $(MAKE) $(addprefix valgrind_,$(ALLEXE))
100
101 wipe: purge
102 $(call TITLE, "Wiping")
103 touch wipe
104 rm -f wipe $(wildcard *.gcda *.gcno *.gcov *.glog)
105 $(call PASS, SUCCESS)
106
107 tests:
108 -rm -f $(ALLEXE)
109 $(MAKE) all
110 $(MAKE) $(addprefix test_,$(ALLEXE))
111
112 ## Main rules
113
114 include $(wildcard *.d)
115 include $(wildcard *.ld)
116
117 gcov_%:
118 $(MAKE) purge
119 $(MAKE) depends
120 OPTIONS="-coverage -O0" $(MAKE) ${@:gcov_%=%}.exe
121 $(MAKE) test_$(@:gcov_%=%)
122 gcov `sed -e 's/\.exe:/.c/;s/\.o/.c/g' $(@:gcov_%=%.ld)`
123 touch gcov
124 rm -f gcov $(wildcard *.gcda *.gcno)
125 $(MAKE) purge
126 grep '^ *#####' *.c.gcov || true
127
128 gprof_%:
129 $(MAKE) purge
130 $(MAKE) depends
131 OPTIONS="-pg" $(MAKE) ${@:gprof_%=%}.exe
132 $(MAKE) ${@:gprof_%=%}.test
133 IFS=$$'\n'; id=1; \
134 for test in `cat ${@:gprof_%=%}.test | sed 's,${@:gprof_%=%}.exe,./${@:gprof_%=%}.exe,g'`; do \
135 log=${@:gprof_%=%}.prof-$$id.glog; \
136 $(call TITLE, test: $$test); \
137 echo $$test > $$log; \
138 eval $$test >> $$log; \
139 [ $$? -eq 0 ] \
140 && echo -e "\033[1;32mSUCCESS\033[0;0m" \
141 || echo -e "\033[1;31mFAILED\033[0;0m"; \
142 [ -f gmon.out ] && { gprof ${@:gprof_%=%}.exe gmon.out >> $$log; rm gmon.out; }; \
143 let id++; \
144 done;
145 $(MAKE) purge
146
147 %.test: %.c
148 $(call TITLE, "Building $@")
149 $(call GETCOMMENTS,test, $<) > $@
150 $(call PASS, SUCCESS)
151 -rm -f _
152
153 test_%: %.test %.exe
154 IFS=$$'\n'; RC=0; \
155 for test in `cat $< | sed 's,${<:.test=.exe},$(VALGRIND) ./${<:.test=.exe},g'`; do \
156 echo "=== $$test ==="; \
157 eval $$test; \
158 [ $$? -eq 0 ] && echo -e "\033[1;32mSUCCESS\033[0;0m" \
159 || { echo -e "\033[1;31mFAILED\033[0;0m"; RC=1; }; \
160 test "$$RC" = 1 -a "$(STOP)" = 1 && break; \
161 done; \
162 test "$$RC" -ne 1
163
164 valgrind_%: %.exe
165 VALGRIND="valgrind -v --leak-check=full --log-fd=3"; \
166 export VALGRIND; \
167 $(MAKE) $(@:valgrind_%=test_%) 3>$@.log
168
169 %.d: %.c
170 $(call TITLE, "Building $@")
171 $(CC) $(INCLUDES) -MM $< -o $@~
172 echo ${<:.c=.o}: $(shell $(call GETCOMMENTS,depends, $<)) >> $@~
173 $(MV) $@~ $@
174 $(call PASS, SUCCESS)
175
176 %.ld: %.c
177 $(call TITLE, "Building $@")
178 echo ${<:.c=.exe}: $(shell $(call GETCOMMENTS,$(LDOPT), $<) | awk '{for (i=1;i<=NF;i++) if ($$(i) ~ /.o$$/) printf " %s", $$(i)}') > $@
179 $(call PASS, SUCCESS)
180
181 %.o: %.c
182 $(call TITLE, "Building $@")
183 $(CC) $(CFLAGS) $(INCLUDES) $(shell $(call GETCOMMENTS,cflags, $<)) -c $< -o $@
184 $(call PASS, SUCCESS)
185
186
187 %.exe: %.o %.d
188 $(call TITLE, "Building $@")
189 $(CC) $(LDFLAGS) $< $(shell $(call GETCOMMENTS,$(LDOPT), ${<:.o=.c})) $(LDLIBS) -o $@
190 $(call PASS, SUCCESS)
191
192 ## Phony
193
194 .PHONY: all analyze clean count depends gcovs purge tests
195
196 ## Precious
197
198 .PRECIOUS: %.d %.o