# Compiler Flags CC := gcc CFLAGS := -g -Wall -Wextra -Werror -pedantic -fno-omit-frame-pointer # Directory variables LIBDIR := lib OBJ := obj INC := include SRC := src TEST := tests # Filepath Pattern Matching LIB := $(LIBDIR)/lib.a SRCS := $(wildcard $(SRC)/*.c) OBJS := $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SRCS)) TESTS := $(wildcard $(TEST)/*.c) TESTBINS := $(patsubst $(TEST)/%.c, $(TEST)/bin/%, $(TESTS)) # Commands must be labeled PHONY .PHONY: all release clean test # Compiler Release Flags release: CFLAGS := -Wall -Wextra -Werror -pedantic -fsanitize=address,undefined -fno-omit-frame-pointer -O2 -DNDEBUG release: clean $(LIB) # Target for compilation. all: $(LIB) # Target / Dependencies $(LIB): $(OBJS) | $(LIBDIR) $(RM) $(LIB) ar -cvrs $@ $^ $(OBJ)/%.o: $(SRC)/%.c $(SRC)/%.h | $(OBJ) $(CC) $(CFLAGS) -c $< -o $@ $(OBJ)/%.o: $(SRC)/%.c | $(OBJ) $(CC) $(CFLAGS) -c $< -o $@ $(TEST)/bin/%: $(TEST)/%.c $(LIB) | $(TEST)/bin $(CC) $(CFLAGS) $< $(LIB) -o $@ # Make directories if none. $(LIBDIR): mkdir $@ $(INC): mkdir $@ $(OBJ): mkdir $@ $(TEST)/bin: mkdir $@ # Run the tests in the bin folder and track results test: $(LIB) $(TESTBINS) @SUCCESS=0; FAILURE=0; \ RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'; \ for t in $(TESTBINS); do \ NAME=$$(basename $$t); \ START=$$(date +%s%N); \ if $$t; then \ RET=0; \ else \ RET=$$?; \ fi; \ END=$$(date +%s%N); \ ELAPSED_NS=$$((END - START)); \ ELAPSED_MS=$$((ELAPSED_NS / 1000000)); \ if [ $$RET -eq 0 ]; then \ printf "%-20s %bPASS%b (%b%4d ms%b)\n" "$$NAME" "$$GREEN" "$$NC" "$$YELLOW" "$$ELAPSED_MS" "$$NC"; \ SUCCESS=$$((SUCCESS + 1)); \ else \ printf "%-20s %bFAIL%b (%b%4d ms%b)\n" "$$NAME" "$$RED" "$$NC" "$$YELLOW" "$$ELAPSED_MS" "$$NC"; \ FAILURE=$$((FAILURE + 1)); \ fi; \ done; \ printf "\nTests completed\n"; \ printf "SUCCESS: %b%d%b\n" "$$GREEN" "$$SUCCESS" "$$NC"; \ printf "FAILURE: %b%d%b\n" "$$RED" "$$FAILURE" "$$NC"; \ test $$FAILURE -eq 0 clean: $(RM) -r $(LIBDIR) $(OBJ) $(TEST)/bin/