forked from cirosantilli/cpp-cheat
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Makefile_many
181 lines (155 loc) · 5.49 KB
/
Makefile_many
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# `make help` for documentation.
-include Makefile_params
# C/CPP
# Don't use the standard names like `CC` and `CXX` to avoid `?=` getting overridden.
# by the Makefile default values.
ALL_DEPEND ?=
MYCC ?= gcc
MYCXX ?= g++
G ?= gdb3
I ?= #-I/usr/include
O ?= 0
STD ?= c11
PEDANTIC ?= -pedantic-errors
CFLAGS ?= -g$(G) -march=native -O$(O) -pthread -std=$(STD) -Wall -Wextra $(PEDANTIC) $(CFLAGS_EXTRA) #-pg
MYCXXFLAGS ?= -g$(G) -march=native -O$(O) -pthread -std=c++17 -Wall -Wextra $(PEDANTIC) $(CXXFLAGS_EXTRA) #-pg
LIBS ?= -lm -lrt $(LIBS_EXTRA) #-lGL -lGLU -lglut
# Fortran
FF ?= gfortran
FFLIBS ?= #-l:lapack/liblapack.so
FFLAGS ?= -O$(O) -std=f2003 -Wextra $(PEDANTIC) $(FFLAGS_EXTRA)
# Paths
IN_DIR ?= ./
IN_EXTS ?= .c .cpp .f
# Unlike in Makefile_one, there is no TMP_DIR because there are no .o files generated.
OUT_DIR ?= ./
OUT_EXT ?= .out
OBJECT_EXT ?= .o
TMP_EXT ?= .tmp
TMP_PREF ?= tmp.
# Basename without extension of file to run on run target.
RUN ?= main
# If exists, will be symlinked into the same directory from which the executable will be run.
# This way, the executable can suppose that this file or directory is in the current directory.
RUN_INPUT ?= input
TEST ?= test
ASSEMBLER_NOEXT ?= $(IN_DIR)$(RUN)
RUN_BNAME := $(RUN)$(OUT_EXT)
INS := $(foreach IN_EXT, $(IN_EXTS), $(wildcard $(IN_DIR)*$(IN_EXT)))
INS_NODIR := $(notdir $(INS))
OUTS_NODIR_NOEXT := $(basename $(INS_NODIR))
OUTS_NOEXT := $(addprefix $(OUT_DIR), $(OUTS_NODIR_NOEXT))
OUTS := $(addsuffix $(OUT_EXT), $(OUTS_NOEXT))
.PHONY: all asm clean debug help mkdir objdump set_objdump_flags profile set_profile_flags test $(PHONY)
all: mkdir $(OUTS)
@#TODO ignore errors if not present
@if [ -e "$(RUN_INPUT)" ] && [ ! -e "$(OUT_DIR)$(RUN_INPUT)" ]; then ln -s ../$(RUN_INPUT) "$(OUT_DIR)$(RUN_INPUT)"; fi
ifneq ($(strip $(run)),)
@echo
cd $(OUT_DIR) && ./"$(run)"
endif
$(OUT_DIR)%$(OUT_EXT): $(IN_DIR)%.c $(ALL_DEPEND)
$(MYCC) $(CFLAGS) $(PROFILE_DEFINE) $(PROFILE_FLAGS) $(I) -o "$@" "$<" $(LIBS)
$(OUT_DIR)%$(OUT_EXT): $(IN_DIR)%.cpp $(ALL_DEPEND)
$(MYCXX) $(MYCXXFLAGS) $(PROFILE_DEFINE) $(PROFILE_FLAGS) $(I) -o "$@" "$<" $(LIBS)
$(OUT_DIR)%$(OUT_EXT): $(IN_DIR)%.f $(ALL_DEPEND)
$(FF) $(FFLAGS) $(PROFILE_DEFINE) $(PROFILE_FLAGS) -o "$@" "$<" $(FFLIBS)
# Make assembly intermingled with original C code to stdout>
# TODO0: how not to rewrite the make rules?
# For bare asm: $(MYCC) $(PROFILE_DEFINE) $(PROFILE_FLAGS) $(CFLAGS) -fverbose-asm -S "$(ASSEMBLER_NOEXT)$$EXT"
asm: mkdir set_asm_flags
for EXT in $(IN_EXTS); do \
if [ -f "$(ASSEMBLER_NOEXT)$$EXT" ]; then \
case "$$EXT" in \
.c)\
$(MYCC) $(PROFILE_DEFINE) $(PROFILE_FLAGS) $(CFLAGS) -c -fverbose-asm -Wa,-adhln "$(ASSEMBLER_NOEXT)$$EXT" $(LIBS) -o $(OUT_DIR)asm.o\
;;\
.cpp)\
$(MYCXX) $(MYCXXFLAGS) $(PROFILE_DEFINE) $(PROFILE_FLAGS) -c -fverbose-asm -Wa,-adhln "$(ASSEMBLER_NOEXT)$$EXT" $(LIBS)\
;;\
.f)\
;;\
esac;\
break;\
fi;\
done
clean:
if [ ! '$(OUT_DIR)' = './' ]; then \
rm -rf '$(OUT_DIR)' ;\
else \
rm -rf *'$(OBJECT_EXT)' *'$(OUT_EXT)' *'$(TMP_EXT)' '$(TMP_PREF)'* callgrind.out.* ;\
fi
if [ -x 'clean' ]; then ./clean; fi
debug: clean set_debug_flags all
cd $(OUT_DIR) && gdb "$(RUN_BNAME)"
mkdir:
@mkdir -p "$(OUT_DIR)"
objdump: mkdir set_objdump_flags all
cd '$(OUT_DIR)' && objdump -CSr '$(RUN_BNAME)'
profile: clean set_profile_flags all run
cd '$(OUT_DIR)' && gprof -b '$(RUN_BNAME)' gmon.out | tee "$(RUN_BNAME).profile_out" | less
run: all
cd $(OUT_DIR) && ./$(RUN_BNAME)
time: all
cd $(OUT_DIR) && time -p ./$(RUN_BNAME)
set_profile_flags:
$(eval PROFILE_FLAGS := -p -pg)
$(eval PROFILE_DEFINE := -DPROFILE)
test: all
@\
if [ -x $(TEST) ]; then \
./$(TEST) '$(OUT_EXT)' ;\
else\
fail=false ;\
for t in *"$(OUT_EXT)"; do\
if ! ./"$$t"; then \
fail=true ;\
break ;\
fi ;\
done ;\
if $$fail; then \
echo "TEST FAILED: $$t" ;\
exit 1 ;\
else \
echo 'ALL TESTS PASSED' ;\
exit 0 ;\
fi ;\
fi ;\
-include Makefile_targets
help:
@echo 'Compiles C files with GCC, and C++ files with g++, Fortran files with gfortran one by one separatelly.'
@echo ''
@echo 'Executables have the same name without extension as the file that originated it:'
@echo ''
@echo ' c.c -> c'
@echo ' cpp.c -> cpp'
@echo ' fortran.f -> fortran'
@echo ''
@echo 'Therefore dont use files with the same basename without extension: e.g. `main.c` and `main.cpp`.'
@echo ''
@echo '# Most useful invocations'
@echo ''
@echo 'Build all:'
@echo ''
@echo ' make'
@echo ''
@echo 'Build and run output with the default basename:'
@echo ''
@echo ' make run'
@echo ''
@echo 'Build and run output with given basename:'
@echo ''
@echo ' make run=c'
@echo ''
@echo 'The `=` sign is *not* optional.'
@echo ''
@echo '# Targets'
@echo ''
@echo 'all ................. Build all.'
@echo 'asm [RUN=name] ...... Print generated assembly code for the file with given basename without extension.'
@echo 'clean ............... Clean built files.'
@echo 'debug ............... Run with `gdb`.'
@echo 'help ................ Print help to stdout.'
@echo 'profile ............. Run with `gprof`.'
@echo 'run[=name] .......... Run a file with the given basename withotu extension or the default not given.'
@echo 'test ................ Run `./test <output-directory> <output-basename> ...`'