diff --git a/Makefile b/Makefile index b26b71b..ba84df3 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ C_FLAG_PEDANTIC = -Wpedantic # Enforce ISO C standard stri C_FLAG_SHADOW = -Wshadow # Warn if a local variable shadows another C_FLAG_STRICT_PROTOS = -Wstrict-prototypes # Warn if function declarations are missing parameter types C_FLAG_NO_UNKNOWN_PRAGMAS = -Wno-unknown-pragmas # Suppress warnings about unknown pragmas +C_FLAG_DEPS = -MMD -MP # Emit per-file header dependency files for incremental rebuilds C_FLAGS = \ $(C_FLAG_STD_C99) \ @@ -18,7 +19,12 @@ C_FLAGS = \ $(C_FLAG_PEDANTIC) \ $(C_FLAG_SHADOW) \ $(C_FLAG_STRICT_PROTOS) \ - $(C_FLAG_NO_UNKNOWN_PRAGMAS) + $(C_FLAG_NO_UNKNOWN_PRAGMAS) \ + $(C_FLAG_DEPS) + +# BUILD-MODE FLAGS +RELEASE_FLAGS = -O2 +DEBUG_FLAGS = -O0 -DDEBUG -fsanitize=address,undefined -fno-omit-frame-pointer # INCLUDE FLGAS INCLUDE_FLAGS = \ @@ -36,28 +42,63 @@ EXTERNAL_FLAGS = \ # CROSS PLATTFORM ifeq ($(OS), Windows_NT) SRC = $(wildcard src\*.c) - TARGET = bin\win\game.exe - RAYLIB_CFLAGS = -I%RAYLIB% + BIN_DIR = bin\win + RAYLIB_CFLAGS = -I%RAYLIB% RAYLIB_LIBS = -L%RAYLIB% -lraylib -lopengl32 -lgdi32 -lwinmm + EXE_EXT = .exe else SRC = $(wildcard src/*.c) - TARGET = bin/unix/game + BIN_DIR = bin/unix RAYLIB_CFLAGS = $(shell pkg-config --cflags raylib) RAYLIB_LIBS = $(shell pkg-config --libs raylib) -lm + EXE_EXT = endif -# CREATE BIN DIR -$(shell mkdir -p bin/unix bin/win) +TARGET_RELEASE = $(BIN_DIR)/game$(EXE_EXT) +TARGET_DEBUG = $(BIN_DIR)/game-debug$(EXE_EXT) + +# PER-FILE OBJECTS (one .o per .c, only stale ones get rebuilt) +OBJ_DIR_RELEASE = build/release +OBJ_DIR_DEBUG = build/debug + +OBJS_RELEASE = $(patsubst src/%.c,$(OBJ_DIR_RELEASE)/%.o,$(SRC)) +OBJS_DEBUG = $(patsubst src/%.c,$(OBJ_DIR_DEBUG)/%.o,$(SRC)) + +DEPS_RELEASE = $(OBJS_RELEASE:.o=.d) +DEPS_DEBUG = $(OBJS_DEBUG:.o=.d) # COMMANDS -build: $(SRC) - $(COMPILER) $(SRC) -o $(TARGET) \ - $(C_FLAGS) \ - $(INCLUDE_FLAGS) \ - $(RAYLIB_LIBS) +build: $(TARGET_RELEASE) + +debug: $(TARGET_DEBUG) + +$(TARGET_RELEASE): $(OBJS_RELEASE) | $(BIN_DIR) + $(COMPILER) $(OBJS_RELEASE) -o $(TARGET_RELEASE) $(RAYLIB_LIBS) + +$(TARGET_DEBUG): $(OBJS_DEBUG) | $(BIN_DIR) + $(COMPILER) $(DEBUG_FLAGS) $(OBJS_DEBUG) -o $(TARGET_DEBUG) $(RAYLIB_LIBS) + +$(OBJ_DIR_RELEASE)/%.o: src/%.c | $(OBJ_DIR_RELEASE) + $(COMPILER) $(C_FLAGS) $(RELEASE_FLAGS) $(INCLUDE_FLAGS) -c $< -o $@ + +$(OBJ_DIR_DEBUG)/%.o: src/%.c | $(OBJ_DIR_DEBUG) + $(COMPILER) $(C_FLAGS) $(DEBUG_FLAGS) $(INCLUDE_FLAGS) -c $< -o $@ + +# DIRECTORIES ARE ORDER-ONLY PREREQUISITES SO `clean` CAN REMOVE THEM WITHOUT +# RACING A CHAINED `build`/`debug` IN THE SAME INVOCATION (e.g. `make clean build`) +$(OBJ_DIR_RELEASE) $(OBJ_DIR_DEBUG) $(BIN_DIR): + mkdir -p $@ + +-include $(DEPS_RELEASE) +-include $(DEPS_DEBUG) clean: - rm -rf $(TARGET) + rm -rf bin build -run: clean build - ./$(TARGET) +run: build + ./$(TARGET_RELEASE) + +run-debug: debug + ./$(TARGET_DEBUG) + +.PHONY: build debug clean run run-debug