# 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 # Platform Detection and Library Linking ifeq ($(OS), Windows_NT) PLATFORM := win32 PLATFORM_SRC := $(SRC)/windows_platform.c PLATFORM_OBJ := $(OBJ)/windows_platform.o PLATFORM_FLAGS := -D WIN32 PLATFORM_LIBS := else UNAME_S := $(shell uname -s) ifeq ($(UNAME_S), Linux) PLATFORM := linux PLATFORM_SRC := $(SRC)/linux_platform.c PLATFORM_OBJ := $(OBJ)/linux_platform.o PLATFORM_FLAGS := -D LINUX PLATFORM_LIBS := -lX11 else ifeq ($(UNAME_S), Darwin) PLATFORM := macos PLATFORM_SRC := $(SRC)/macos_platform.c PLATFORM_OBJ := $(OBJ)/macos_platform.o PLATFORM_FLAGS := -D MACOS PLATFORM_LIBS := else $(error Unsupported platform: $(UNAME_S)) endif endif CFLAGS += $(PLATFORM_FLAGS) # Filepath Pattern Matching LIB := $(LIBDIR)/lib.a # Exclude platform files from wildcard, add the correct one back in SRCS := $(filter-out $(SRC)/windows_platform.c $(SRC)/linux_platform.c $(SRC)/macos_platform.c, \ $(wildcard $(SRC)/*.c)) $(PLATFORM_SRC) 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 $(PLATFORM_FLAGS) release: clean $(LIB) # Target for compilation. all: $(LIB) @echo "Built for platform: $(PLATFORM)" # 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) $(PLATFORM_LIBS) -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/