-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMakefile
executable file
·462 lines (365 loc) · 15.8 KB
/
Makefile
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
################################################################################
# Makefile
################################################################################
# Makefile by fletcher97
# Version: 2.4
# Repo: www.github.com/fletcher97/utils
# v2.4: Added PEDANTIC variable on configs section. If set to true a lot of
# warning flags will be added to use while compiling. By default this feature is
# turned on. Setting the variable to anything else will disable extra warnings.
# Turning it off will still compile with -Wall -Wextra -Werror.
#
# A LANG variable was aslo added to to specify what language the program is
# using so as to be able to detect the extentions of the files (not implemented)
# and enable more warnings.
# v2.3: A rule to check if a program can be compiled was added in other to be
# used for git hooks. A folder with hooks can be found in the same repository
# this makefile came from.
# As of version 2.2 this Makefile expects an asan.c file to be present in the
# asan folder inside the SRC_ROOT directory. A copy of the file is provided
# with the Makefile. Also it now uses clang instead of gcc.
# This makefile can be copied to a directory and it will generate the file
# structure and initialize a git repository with the .init rule. Any variables
# and rules for the specific project can be added in the appropriate section.
# By default this makefile assumes that libft, 42's student made library, a copy
# of which can be obtained by cloning https://github.com/fletcher97/libft.git,
# is being used. It can be removed by simply commenting any reference to it on
# the library section.
################################################################################
# Project Variables
################################################################################
# Name of a single binary. Add as many variables as required by the project
NAME1 := TicTacToe
# The names of all the binaries. Add aditional variables created above separated
# by space.
NAMES := ${NAME1}
################################################################################
# Configs
################################################################################
# Verbose levels
# 0: Make will be totaly silenced
# 1: Make will print echos and printf
# 2: Make will not be silenced but target commands will not be printed
# 3: Make will print each command
# 4: Make will print all debug info
#
# If no value is specified or an incorrect value is given make will print each
# command like if VERBOSE was set to 3.
VERBOSE := 1
# Version 2.1 and above of this makefile can generate targets to use other
# makefiles as dependencies. This feature will execute the rule of same name in
# an other makefile. This can be usefull in many situation but also a hinderence
# in others. If for example you just want to clean the root directory the clean
# rule will be executed in any other makefile specified. You can deactivate the
# creation of these targets by setting the bellow variable to 0.
CREATE_LIB_TARGETS := 0
# Pedantic allows for extra warning flags to be used while compiling. If set to
# true these flags are applied. If set to anything else the flags will not be
# used. By default it's turned on.
PEDANTIC := true
# Specify the language use by your program. This will allow to detect file
# extentions automatically (not implemented). It also allows fo warnings to be
# activated/deactivated based on the language used.
LANG := C
################################################################################
# Compiler & Flags
################################################################################
# Compiler
CC := clang
# Compiler flags
CFLAGS := -Wall -Wextra -Werror
# Pedantic flags
ifeq (${PEDANTIC},true)
CFLAGS += -Wpedantic -Werror=pedantic -pedantic-errors -Wcast-align
CFLAGS += -Wcast-qual -Wdisabled-optimization -Wformat=2 -Wuninitialized
CFLAGS += -Winit-self -Wmissing-include-dirs -Wredundant-decls -Wshadow
CFLAGS += -Wstrict-overflow=5 -Wundef -fdiagnostics-show-option
CFLAGS += -fstack-protector-all -fstack-clash-protection
ifeq (${CC},gcc)
CFLAGS += -Wformat-signedness -Wformat-truncation=2 -Wformat-overflow=2
CFLAGS += -Wlogical-op -Wstringop-overflow=4
endif
ifeq (${LANG},C++)
CFLAGS += -Wctor-dtor-privacy -Wold-style-cast -Woverloaded-virtual
CFLAGS += -Wsign-promo
ifeq (${CC},gcc)
CFLAGS += -Wstrict-null-sentinel -Wnoexcept
endif
endif
endif
# Generic debug flags
DFLAGS := -g
# Address sanitizing flags
ASAN := -fsanitize=address -fsanitize-recover=address
ASAN += -fno-omit-frame-pointer -fno-common
ASAN += -fsanitize=pointer-subtract -fsanitize=pointer-compare
# Technicaly UBSan but works with ASan
ASAN += -fsanitize=undefined
# Technicaly LSan but works with ASan
ASAN += -fsanitize=leak
# Thread sanitizing flags
TSAN := -fsanitize=thread
# Memory sanitizing flags
MSAN := -fsanitize=memory -fsanitize-memory-track-origins
################################################################################
# Root Folders
################################################################################
BIN_ROOT := bin/
DEP_ROOT := dep/
INC_ROOT := inc/
LIB_ROOT := lib/
OBJ_ROOT := obj/
SRC_ROOT := src/
################################################################################
# Libraries
################################################################################
# Libft
#LIBFT_ROOT := ${LIB_ROOT}libft/
#LIBFT_INC := ${LIBFT_ROOT}inc/
#LIBFT := ${LIBFT_ROOT}bin/libft.a
#INC_DIRS += ${LIBFT_INC}
#LIBS += -L${LIBFT_ROOT}bin -lft
# Libraries for which to create default targets. All libraries in this list will
# have targets created autimatically. The targets that are created are set in
# DEFAULT_LIB_RULES. The targets will have to format <library root>//<target>
# and it will invoke make as follows:
# `make -C <library root> <rule>`
#DEFAULT_LIBS := ${LIBFT_ROOT}
# Default targets to create for libraries specified in DEFAULT_LIBS. This is a
# small list of common targets in most makefiles.
DEFAULT_LIB_RULES := all clean re
# All projects with a copy of this makefile v2.1 and up ate garanteed to work
# with these targets. If you wish to not use them just comment the lines you
# don't want.
DEFAULT_LIB_RULES += fclean clean_all clean_dep
DEFAULT_LIB_RULES += debug debug_re debug_asan debug_asan_re
# All projects with a copy of this makefile v2.2 and up ate garanteed to work
# with these targets. If you wish to not use them just comment the lines you
# don't want.
DEFAULT_LIB_RULES += debug_tsan debug_tsan_re debug_msan debug_msan_re
################################################################################
# Content Folders
################################################################################
# Lists of ':' separated folders inside SRC_ROOT containing source files. Each
# folder needs to end with a '/'. The path to the folders is relative to
# SRC_ROOTIf SRC_ROOT contains files './' needs to be in the list. Each list is
# separated by a space or by going to a new line and adding onto the var.
# Exemple:
# DIRS := folder1/:folder2/
# DIRS += folder1/:folder3/:folder4/
DIRS := ./:input/
SRC_DIRS_LIST := $(addprefix ${SRC_ROOT},${DIRS})
SRC_DIRS_LIST := $(foreach dl,${SRC_DIRS_LIST},$(subst :,:${SRC_ROOT},${dl}))
SRC_DIRS = $(call rmdup,$(subst :,${SPACE},${SRC_DIRS_LIST}))
OBJ_DIRS = $(subst ${SRC_ROOT},${OBJ_ROOT},${SRC_DIRS})
DEP_DIRS = $(subst ${SRC_ROOT},${DEP_ROOT},${SRC_DIRS})
# List of folders with header files.Each folder needs to end with a '/'. The
# path to the folders is relative to the root of the makefile. Library includes
# can be specified here.
INC_DIRS += ${INC_ROOT}
################################################################################
# Files
################################################################################
SRCS_LIST = $(foreach dl,${SRC_DIRS_LIST},$(subst ${SPACE},:,$(strip $(foreach\
dir,$(subst :,${SPACE},${dl}),$(wildcard ${dir}*.c)))))
OBJS_LIST = $(subst ${SRC_ROOT},${OBJ_ROOT},$(subst .c,.o,${SRCS_LIST}))
SRCS = $(foreach dir,${SRC_DIRS},$(wildcard ${dir}*.c))
OBJS = $(subst ${SRC_ROOT},${OBJ_ROOT},${SRCS:.c=.o})
DEPS = $(subst ${SRC_ROOT},${DEP_ROOT},${SRCS:.c=.d})
INCS := ${addprefix -I,${INC_DIRS}}
BINS := ${addprefix ${BIN_ROOT},${NAMES}}
################################################################################
# Conditions
################################################################################
ifeq ($(shell uname),Linux)
SED := sed -i.tmp --expression
else ifeq ($(shell uname),Darwin)
SED := sed -i.tmp
endif
ifeq ($(VERBOSE),0)
MAKEFLAGS += --silent
BLOCK := &>/dev/null
else ifeq ($(VERBOSE),1)
MAKEFLAGS += --silent
else ifeq ($(VERBOSE),2)
AT := @
else ifeq ($(VERBOSE),4)
MAKEFLAGS += --debug=v
endif
ifeq (${CREATE_LIB_TARGETS},0)
undefine DEFAULT_LIBS
endif
################################################################################
# VPATHS
################################################################################
vpath %.o $(OBJ_ROOT)
vpath %.h $(INC_ROOT)
vpath %.c $(SRC_DIRS)
vpath %.d $(DEP_DIRS)
################################################################################
# Project Target
################################################################################
all: ${BINS}
.SECONDEXPANSION:
${BIN_ROOT}${NAME1}: $$(call get_files,$${@F},$${OBJS_LIST})
${AT}printf "\033[33m[CREATING ${@F}]\033[0m\n" ${BLOCK}
${AT}mkdir -p ${@D} ${BLOCK}
${AT}${CC} ${CFLAGS} ${INCS} ${ASAN_FILE}\
$(call get_files,${@F},${OBJS_LIST}) ${LIBS} -o $@ ${BLOCK}
################################################################################
# Clean Targets
################################################################################
clean: $$(call get_lib_target,$${DEFAULT_LIBS},$$@)
${AT}printf "\033[38;5;1m[REMOVING OBJECTS]\033[0m\n" ${BLOCK}
${AT}mkdir -p ${OBJ_ROOT} ${BLOCK}
${AT}find ${OBJ_ROOT} -type f -name "*.o" -delete ${BLOCK}
fclean: $$(call get_lib_target,$${DEFAULT_LIBS},$$@)
${AT}printf "\033[38;5;1m[REMOVING OBJECTS]\033[0m\n" ${BLOCK}
${AT}mkdir -p ${OBJ_ROOT} ${BLOCK}
${AT}find ${OBJ_ROOT} -type f -name "*.o" -delete ${BLOCK}
${AT}printf "\033[38;5;1m[REMOVING BINARIES]\033[0m\n" ${BLOCK}
${AT}mkdir -p ${BIN_ROOT} ${BLOCK}
${AT}find ${BIN_ROOT} -type f\
$(addprefix -name ,${NAMES}) -delete ${BLOCK}
clean_dep: $$(call get_lib_target,$${DEFAULT_LIBS},$$@)
${AT}printf "\033[38;5;1m[REMOVING DEPENDENCIES]\033[0m\n" ${BLOCK}
${AT}mkdir -p ${DEP_ROOT} ${BLOCK}
${AT}find ${DEP_ROOT} -type f -name "*.d" -delete ${BLOCK}
clean_all: fclean clean_dep
re: fclean all
################################################################################
# Debug Targets
################################################################################
debug: CFLAGS += ${DFLAGS}
debug: $$(call get_lib_target,$${DEFAULT_LIBS},$$@) all
obj/asan/asan.o: src/asan/asan.c
${AT}mkdir -p ${@D} ${BLOCK}
${AT}${CC} -o $@ -c $< ${BLOCK}
debug_asan: CFLAGS += ${DFLAGS} ${ASAN}
debug_asan: ASAN_FILE = obj/asan/asan.o
debug_asan: $$(call get_lib_target,$${DEFAULT_LIBS},$$@) obj/asan/asan.o all
debug_tsan: CFLAGS += ${DFLAGS} ${TSAN}
debug_tsan: $$(call get_lib_target,$${DEFAULT_LIBS},$$@) all
debug_msan: CFLAGS += ${DFLAGS} ${MSAN}
debug_msan: $$(call get_lib_target,$${DEFAULT_LIBS},$$@) all
debug_re: fclean debug
debug_asan_re: fclean debug_asan
debug_tsan_re: fclean debug_tsan
debug_msan_re: fclean debug_msan
################################################################################
# Utility Targets
################################################################################
.init:
${AT}printf "\033[33m[CREATING FOLDER STRUCTURE]\033[0m\n" ${BLOCK}
${AT}mkdir -p ${BIN_ROOT} ${BLOCK}
${AT}mkdir -p ${DEP_ROOT} ${BLOCK}
${AT}mkdir -p ${INC_ROOT} ${BLOCK}
${AT}mkdir -p ${OBJ_ROOT} ${BLOCK}
${AT}mkdir -p ${SRC_ROOT} ${BLOCK}
${AT}printf "\033[33m[INITIALIZING GIT REPOSITORY]\033[0m\n" ${BLOCK}
${AT}git init ${BLOCK}
${AT}echo "*.o\n*.d\n.vscode\na.out\n.DS_Store\nbin/\n*.ignore"\
> .gitignore ${BLOCK}
${AT}date > $@ ${BLOCK}
${AT}printf "\033[33m[CREATING FIRST COMMIT]\033[0m\n" ${BLOCK}
${AT}git add .gitignore ${BLOCK}
${AT}git add $@ ${BLOCK}
${AT}git add Makefile ${BLOCK}
${AT}git commit -m "init" ${BLOCK}
# Meta target to force a target to be executed
.FORCE: ;
# Print a specifique variable
print-%: ; @echo $*=$($*)
# List all the targets in alphabetical order
targets:
${AT}${MAKE} LC_ALL=C -pRrq -f ${CURRENT_FILE} : 2>/dev/null\
| awk -v RS= -F: '/^# File/,/^# files hash-table stats/\
{if ($$1 !~ "^[#]") {print $$1}}\
{if ($$1 ~ "# makefile") {print $$2}}'\
| sort
compile-test: ${addprefix compile-test/,${NAMES}}
################################################################################
# .PHONY
################################################################################
# Phony clean targets
.PHONY: clean fclean clean_dep clean_all
# Phony debug targets
.PHONY: debug debug_re debug_asan debug_asan_re debug_tsan debug_tsan_re
# Phony utility targets
.PHONY: targets .FORCE compile-test
# Phony execution targets
.PHONY: re all
################################################################################
# Constantes
################################################################################
NULL =
SPACE = ${NULL} #
CURRENT_FILE = ${MAKEFILE_LIST}
################################################################################
# Functions
################################################################################
# Get the index of a given word in a list
_index = $(if $(findstring $1,$2),$(call _index,$1,\
$(wordlist 2,$(words $2),$2),x $3),$3)
index = $(words $(call _index,$1,$2))
# Get value at the same index
lookup = $(word $(call index,$1,$2),$3)
# Remove duplicates
rmdup = $(if $1,$(firstword $1) $(call rmdup,$(filter-out $(firstword $1),$1)))
# Get files for a specific binary
get_files = $(subst :,${SPACE},$(call lookup,$1,${NAMES},$2))
# Get default target for libs given a rule
get_lib_target = $(foreach lib,$1,${lib}/$2)
################################################################################
# Target Templates
################################################################################
define make_bin_def
${1}: ${2}
endef
define make_obj_def
${1}: ${2} ${3}
$${AT}printf "\033[38;5;14m[OBJ]: \033[38;5;47m$$@\033[0m\n" $${BLOCK}
$${AT}mkdir -p $${@D} $${BLOCK}
$${AT}$${CC} $${CFLAGS} $${INCS} -c $$< -o $$@ $${BLOCK}
endef
define make_dep_def
${1}: ${2}
$${AT}printf "\033[38;5;13m[DEP]: \033[38;5;47m$$@\033[0m\n" $${BLOCK}
$${AT}mkdir -p $${@D} $${BLOCK}
$${AT}$${CC} -MM $$< $${INCS} -MF $$@ $${BLOCK}
$${AT}$${SED} 's|:| $$@ :|' $$@ $${SED_END} $${BLOCK}
$${AT}$${SED} '1 s|^|$${@D}/|' $$@ && rm -f $$@.tmp $${BLOCK}
$${AT}$${SED} '1 s|^$${DEP_ROOT}|$${OBJ_ROOT}|' $$@\
&& rm -f $$@.tmp $${BLOCK}
endef
define make_lib_def
${1}/${2}: .FORCE
make -C ${1} ${2}
endef
define make_compile_test_def
compile-test/${1}: .FORCE
$${AT}printf "\033[33m[TESTING $${@F}]\033[0m\n" $${BLOCK}
$${AT}$${CC} $${CFLAGS} -fsyntax-only $${INCS} $${ASAN_FILE}\
$$(call get_files,$${@F},$${SRCS_LIST}) $${BLOCK}
endef
################################################################################
# Target Generator
################################################################################
ifneq (${BIN_ROOT},./)
$(foreach bin,${BINS},$(eval\
$(call make_bin_def,$(notdir ${bin}),${bin})))
endif
$(foreach src,${SRCS},$(eval\
$(call make_dep_def,$(subst ${SRC_ROOT},${DEP_ROOT},${src:.c=.d}),${src})))
$(foreach src,${SRCS},$(eval\
$(call make_obj_def,$(subst ${SRC_ROOT},${OBJ_ROOT},${src:.c=.o}),\
${src},\
$(subst ${SRC_ROOT},${DEP_ROOT},${src:.c=.d}))))
$(foreach lib,${DEFAULT_LIBS},$(foreach target,${DEFAULT_LIB_RULES},$(eval\
$(call make_lib_def,${lib},${target}))))
$(foreach name,$(NAMES),$(eval\
$(call make_compile_test_def,${name})))
################################################################################
# Includes
################################################################################
-include ${DEPS}