1 | # Preamble >> Make config |
2 | SHELL := bash |
3 | .ONESHELL: |
4 | .SHELLFLAGS := -eu -o pipefail -c |
5 | .DELETE_ON_ERROR: |
6 | MAKEFLAGS += --warn-undefined-variables |
7 | MAKEFLAGS += --no-builtin-rules |
8 |
|
9 | ifeq ($(origin .RECIPEPREFIX), undefined) |
10 | $(error This Make does not support .RECIPEPREFIX. Please use GNU Make 4.0 or later) |
11 | endif |
12 | .RECIPEPREFIX = > |
13 |
|
14 |
|
15 | # Custom Make settings |
16 | PROJECT_NAME := minesweeper |
17 |
|
18 | CC := gcc -std=c11 |
19 | CFLAGS := -O3 |
20 | CWARNINGS := -Werror -Wall -Wextra -pedantic |
21 | CINCLUDES := -Isrc |
22 | CLIBS := -lncurses |
23 |
|
24 | CFORMAT := clang-format -i |
25 | CTIDY := clang-tidy --checks=-*,clang-analyzer-*,-clang-analyzer-cplusplus-* |
26 |
|
27 | SOURCE_DIR := src |
28 | BIN_DIR := bin |
29 |
|
30 | # Inputs and outputs |
31 | SOURCES := $(shell find $(SOURCE_DIR) -name *.c) |
32 | HEADERS := $(shell find $(SOURCE_DIR) -name *.h) |
33 | OBJECTS := $(patsubst %.c, $(BIN_DIR)/%.o, $(SOURCES)) |
34 | OUTFILE := $(BIN_DIR)/$(PROJECT_NAME) |
35 |
|
36 |
|
37 | # Make target config |
38 | .PHONY: all prelint postlint lint precompile postcompile compile prebuild postbuild build clean run done |
39 | all: lint compile build run done |
40 |
|
41 |
|
42 | # Automatically create targets and gather their prerequisites |
43 | define create-ctarget |
44 | $1 |
45 | > @echo -en "\e[37m[\e[34m?\e[37m]\e[0m $$< \e[36m⇒\e[0m $$@" |
46 | > @mkdir -p $$(dir $$@) |
47 | > @if $(CC) -o $$@ -c $(CFLAGS) $(CWARNINGS) $(CINCLUDES) $$<>/dev/null 2>&1; |
48 | > @then echo -e "\r\e[37m[\e[32m✓\e[37m]\e[0m"; |
49 | > @else echo -e "\r\e[37m[\e[31m✗\e[37m]\e[0m"; |
50 | > @$(CC) -o $$@ -c $(CFLAGS) $(CWARNINGS) $(CINCLUDES) $$<; |
51 | > @fi |
52 | endef |
53 |
|
54 | compile: precompile $(OBJECTS) postcompile |
55 | precompile: |
56 | > @echo -e "\e[1m\e[35mCOMPILING\e[0m" |
57 | postcompile: |
58 | > @echo -e "\e[94mDone compiling\e[0m\n" |
59 | _MM_BACKSLASH := $\\ |
60 | $(foreach src,$(SOURCES),$(eval $(call create-ctarget,$(filter-out ${_MM_BACKSLASH},$(shell $(CC) -MM -MT $(patsubst %.c, $(BIN_DIR)/%.o, $(src)) $(src)))))) |
61 |
|
62 |
|
63 | # Link and build outfile |
64 | build: prebuild $(OUTFILE) postbuild |
65 | prebuild: |
66 | > @echo -e "\e[1m\e[35mLINKING\e[0m" |
67 | postbuild: |
68 | > @echo -e "\e[94mDone linking\e[0m\n" |
69 | $(OUTFILE): $(OBJECTS) |
70 | > @echo -en "\e[37m[\e[34m?\e[37m]\e[0m $^ \e[36m⇒\e[0m $@" |
71 | > @mkdir -p $(dir $@) |
72 | > @if $(CC) -o $@ $^ $(CLIBS)>/dev/null 2>&1; |
73 | > @then echo -e "\r\e[37m[\e[32m✓\e[37m]\e[0m"; |
74 | > @else echo -e "\r\e[37m[\e[31m✗\e[37m]\e[0m"; |
75 | > @$(CC) -o $@ $^ $(CLIBS); |
76 | > @fi |
77 |
|
78 | done: |
79 | > @echo -e "\e[1m\e[48;5;28m\e[37mDone!\e[0m" |
80 |
|
81 |
|
82 | # Run outfile |
83 | run: $(OUTFILE) |
84 | > @echo -e "\e[1m\e[93m=== [ PROGRAM OUTPUT ] ===\e[0m" |
85 | > $(OUTFILE) |
86 | > @echo -e "\e[1m\e[93m==========================\e[0m\n" |
87 |
|
88 |
|
89 | # Create linter targets for source and header files |
90 | define create-linttarget |
91 | $1 |
92 | > @echo -en "\e[37m[\e[34m?\e[37m]\e[0m $$<" |
93 | > @if ! $(CFORMAT) $$<>/dev/null 2>&1; |
94 | > @then echo -e "\r\e[37m[\e[31m✗\e[37m]\e[0m"; |
95 | > @$(CFORMAT) $$<; |
96 | > @fi; |
97 | > @if $(CTIDY) $$<>/dev/null 2>&1; |
98 | > @then echo -e "\r\e[37m[\e[32m✓\e[37m]\e[0m"; |
99 | > @else echo -e "\r\e[37m[\e[31m✗\e[37m]\e[0m"; |
100 | > @$(CTIDY) $$<; |
101 | > @fi; |
102 | > @mkdir -p $$(dir $$@) |
103 | > @touch $$@ |
104 | endef |
105 |
|
106 | # Translate %.(c|h) to bin/%.(c|h)l and create targets for their sources |
107 | $(foreach src,$(SOURCES),$(eval $(call create-linttarget,$(patsubst %.c, $(BIN_DIR)/%.cl, $(src)): $(src)))) |
108 | $(foreach header,$(HEADERS),$(eval $(call create-linttarget,$(patsubst %.h, $(BIN_DIR)/%.hl, $(header)): $(header)))) |
109 |
|
110 | lint: prelint $(patsubst %.h, $(BIN_DIR)/%.hl, $(HEADERS)) $(patsubst %.c, $(BIN_DIR)/%.cl, $(SOURCES)) postlint |
111 | prelint: |
112 | > @echo -e "\e[1m\e[35mLINTING\e[0m" |
113 | postlint: |
114 | > @echo -e "\e[94mDone linting\e[0m\n" |
115 |
|
116 |
|
117 | # Clean target |
118 | clean: |
119 | > @rm -r $(BIN_DIR) |
120 |
|