generic makefile
[calc.git] / makefile
... / ...
CommitLineData
1# Default flags
2
3CC = gcc
4
5#INCLUDES = -I../debug -D__MEMORY_ALLOCATION__
6INCLUDES =
7OFLAGS = -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
14CFLAGS += -W -Wall -Wextra -g
15#CFLAGS += -std=c99 -D_XOPEN_SOURCE=500
16CFLAGS += $(OFLAGS) $(INCLUDES) $(OPTIONS)
17LDFLAGS += -g $(LDOPTS) $(OPTIONS)
18
19LDOPT = linker
20MV = mv
21ifneq (, $(findstring linux, $(MAKE_HOST)))
22# Linux
23else ifneq (, $(findstring mingw, $(MAKE_HOST)))
24# Windows MinGw
25CFLAGS += -DWIN32
26#LDLIBS += -lws2_32
27LDOPT = winlnk
28else ifneq (, $(findstring cygwin, $(MAKE_HOST)))
29CFLAGS += -DWIN32
30# Windows CygWin
31LDOPT = winlnk
32else ifneq (, $(findstring msdos, $(MAKE_HOST)))
33# MSDOS
34LDOPT = doslnk
35MV = move
36endif
37
38# Targets
39
40ALLEXE = $(shell for f in *.c; do grep -q '/\*\slinker:' $$f && echo $${f/.c}; done)
41
42SHELL = bash
43
44#MAKE = mingw32-make
45MAKEFLAGS += -s
46include $(wildcard .makefile)
47
48# Functions
49
50TITLE = echo -en "\033[0;1m$(strip $(1))\033[0;0m:\t"
51PASS = echo -e "\033[1;32m$(strip $(1))\033[0;0m"
52WARN = echo -e "\033[1;33m$(strip $(1))\033[0;0m"
53FAIL = echo -e "\033[1;31m$(strip $(1))\033[0;0m"
54
55MKDIR = mkdir -p $(1) && chmod a+rx,go-w $(1)
56
57INSTALL = test -d `dirname $(2)` || $(call MKDIR, `dirname $(2)`) && cp -pa $(1) $(2) && chmod a+rX,go-w $(2)
58
59VALID = $(call TITLE, $(1)) && $(2) && $(call PASS, SUCCESS) || { $(call FAIL, FAILED); test; }
60
61GETCOMMENTS = 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
66all: depends
67 $(MAKE) $(ALLEXE:%=%.exe)
68
69analyze:
70 make purge
71 scan-build make
72 #scan-build -stats make
73
74count:
75 wc $(wildcard *.c *.h) $(MAKEFILE_LIST)
76
77clean:
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
83depends: $(patsubst %.c, %.d, $(wildcard *.c)) $(patsubst %, %.ld, $(ALLEXE))
84
85gcovs:
86 $(MAKE) $(addprefix gcov_,$(ALLEXE))
87
88gprofs:
89 $(MAKE) $(addprefix gprof_,$(ALLEXE))
90
91purge: clean
92 $(call TITLE, "Purging")
93 touch purge
94 rm -f purge $(ALLEXE:%=%.exe)
95 $(call PASS, SUCCESS)
96
97valgrinds:
98 $(MAKE) all
99 $(MAKE) $(addprefix valgrind_,$(ALLEXE))
100
101wipe: purge
102 $(call TITLE, "Wiping")
103 touch wipe
104 rm -f wipe $(wildcard *.gcda *.gcno *.gcov *.glog)
105 $(call PASS, SUCCESS)
106
107tests:
108 -rm -f $(ALLEXE)
109 $(MAKE) all
110 $(MAKE) $(addprefix test_,$(ALLEXE))
111
112## Main rules
113
114include $(wildcard *.d)
115include $(wildcard *.ld)
116
117gcov_%:
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
128gprof_%:
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
153test_%: %.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
164valgrind_%: %.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