| 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 | # Compiler settings |
| 16 | CC := gcc -std=c11 |
| 17 | CFLAGS := -O3 |
| 18 | CWARNINGS := -Werror -Wall -Wextra -pedantic |
| 19 | CINCLUDES := -Isrc |
| 20 | CLIBS := -lncurses |
| 21 |
|
| 22 | CFORMAT := clang-format -i |
| 23 | CTIDY := clang-tidy --checks=-*,clang-analyzer-*,-clang-analyzer-cplusplus-* |
| 24 |
|
| 25 | SOURCE_DIR := src |
| 26 | BIN_DIR := bin |
| 27 | SOURCES := $(wildcard $(SOURCE_DIR)/*.c) |
| 28 | HEADERS := $(wildcard $(SOURCE_DIR)/*.h) |
| 29 | OBJECTS := $(patsubst %.c, $(BIN_DIR)/%.o, $(SOURCES)) |
| 30 | OUTFILE := $(BIN_DIR)/minesweeper |
| 31 |
|
| 32 | .PHONY: all lint precompile postcompile compile build clean run done |
| 33 | all: lint compile build run done |
| 34 |
|
| 35 |
|
| 36 | # Automatically create targets and gather their prerequisites |
| 37 | define create-ctarget |
| 38 | $1 |
| 39 | > @echo -en "\e[37m[\e[34m?\e[37m]\e[0m $$< \e[36m⇒\e[0m $$@" |
| 40 | > @mkdir -p $$(dir $$@) |
| 41 | > @if $(CC) -o $$@ -c $(CFLAGS) $(CWARNINGS) $(CINCLUDES) $$<>/dev/null 2>&1; |
| 42 | > @then echo -e "\r\e[37m[\e[32m✓\e[37m]\e[0m"; |
| 43 | > @else echo -e "\r\e[37m[\e[31m✗\e[37m]\e[0m"; |
| 44 | > @$(CC) -o $$@ -c $(CFLAGS) $(CWARNINGS) $(CINCLUDES) $$<; |
| 45 | > @fi |
| 46 | endef |
| 47 |
|
| 48 | compile: precompile $(OBJECTS) postcompile |
| 49 | precompile: |
| 50 | > @echo -e "\e[1m\e[35mCOMPILING\e[0m" |
| 51 | postcompile: |
| 52 | > @echo -e "\e[94mDone compiling\e[0m\n" |
| 53 | $(foreach src,$(SOURCES),$(eval $(call create-ctarget,$(shell $(CC) -MM -MT $(patsubst %.c, $(BIN_DIR)/%.o, $(src)) $(src))))) |
| 54 |
|
| 55 |
|
| 56 | # Link and build outfile |
| 57 | build: $(OUTFILE) |
| 58 | $(OUTFILE): $(OBJECTS) |
| 59 | > @echo -e "\e[1m\e[35mLINKING\e[0m" |
| 60 | > @echo -en "\e[37m[\e[34m?\e[37m]\e[0m $^ \e[36m⇒\e[0m $@" |
| 61 | > @mkdir -p $(dir $@) |
| 62 | > @if $(CC) -o $@ $^ $(CLIBS)>/dev/null 2>&1; |
| 63 | > @then echo -e "\r\e[37m[\e[32m✓\e[37m]\e[0m"; |
| 64 | > @else echo -e "\r\e[37m[\e[31m✗\e[37m]\e[0m"; |
| 65 | > @$(CC) -o $@ $^ $(CLIBS); |
| 66 | > @fi |
| 67 | > @echo -e "\e[94mDone linking\e[0m\n" |
| 68 | done: |
| 69 | > @echo -e "\e[1m\e[48;5;28m\e[37mDone!\e[0m" |
| 70 |
|
| 71 |
|
| 72 | # Run out |
| 73 | run: $(OUTFILE) |
| 74 | > @$(OUTFILE) |
| 75 |
|
| 76 |
|
| 77 | # Create linter targets for source and header files |
| 78 | define create-linttarget |
| 79 | $1 |
| 80 | > @echo -en "\e[37m[\e[34m?\e[37m]\e[0m $$<" |
| 81 | > @if ! $(CFORMAT) $$<>/dev/null 2>&1; |
| 82 | > @then echo -e "\r\e[37m[\e[31m✗\e[37m]\e[0m"; |
| 83 | > @$(CFORMAT) $$<; |
| 84 | > @fi; |
| 85 | > @if $(CTIDY) $$<>/dev/null 2>&1; |
| 86 | > @then echo -e "\r\e[37m[\e[32m✓\e[37m]\e[0m"; |
| 87 | > @else echo -e "\r\e[37m[\e[31m✗\e[37m]\e[0m"; |
| 88 | > @$(CTIDY) $$<; |
| 89 | > @fi; |
| 90 | > @mkdir -p $$(dir $$@) |
| 91 | > @touch $$@ |
| 92 | endef |
| 93 |
|
| 94 | $(foreach src,$(SOURCES),$(eval $(call create-linttarget,$(patsubst %.c, $(BIN_DIR)/%.cl, $(src)): $(src)))) |
| 95 | $(foreach header,$(HEADERS),$(eval $(call create-linttarget,$(patsubst %.h, $(BIN_DIR)/%.hl, $(header)): $(header)))) |
| 96 |
|
| 97 | prelint: |
| 98 | > @echo -e "\e[1m\e[35mLINTING\e[0m" |
| 99 | postlint: |
| 100 | > @echo -e "\e[94mDone linting\e[0m\n" |
| 101 | lint: prelint $(patsubst %.h, $(BIN_DIR)/%.hl, $(HEADERS)) $(patsubst %.c, $(BIN_DIR)/%.cl, $(SOURCES)) postlint |
| 102 |
|
| 103 |
|
| 104 | # Clean |
| 105 | clean: |
| 106 | > @rm -r $(BIN_DIR) |
| 107 |
|