11# ==============================================================================
2- # Basic C++ Makefile Template
2+ # C++ Makefile Template - Donut Example
33# Author: Dayron Mustelier (@DMsuDev) - 2025/2026
44# License: MIT
55# ==============================================================================
66
77# Default build type when running plain `make`
88.DEFAULT_GOAL := all
99
10+ # Ensure consistent behavior across make versions
11+ .SUFFIXES :
12+
1013# ─── Main configuration ───────────────────────────────────────────────────────
1114
12- APP_NAME ?= ProjectName
15+ APP_NAME ?= donut
1316SRC_EXT ?= cpp
1417LANGUAGE ?= c++23
1518CXX ?= g++
1619USE_CONSOLE ?= true
1720
18-
1921# ─── Directories & Paths ──────────────────────────────────────────────────────
2022
21- # Can be a list separate by spaces " ": include/ src/ src/ core imgui/
23+ # Can be a list separated by spaces: src include src/core
2224SOURCE_DIRS ?= src
2325INCLUDE_DIRS ?= include
2426
25- BUILD_BASE := build
26- BIN_DIR := $(BUILD_BASE ) /bin
27+ BUILD_BASE := ./ build
28+ BIN_DIR := $(BUILD_BASE ) /app
2729OBJ_DIR := $(BUILD_BASE ) /obj
2830DEP_DIR := $(BUILD_BASE ) /dep
2931
3032# ─── Compiler & Linker flags (base) ─────────────────────────────────────────────
3133
3234CXXFLAGS_BASE := -std=$(LANGUAGE ) -fdiagnostics-color=always
3335
34- # Set flags that control and shows the error of the compiler
35- # If type -Werror the compiler when throw error message stop the compilation.
36+ # Set flags that control and show compiler errors
3637ERRORFLAGS := -Wall -Wextra -pedantic-errors
3738
3839CXXFLAGS := $(CXXFLAGS_BASE ) $(ERRORFLAGS )
39- LDFLAGS :=
40+ LDFLAGS ?= -L./lib
41+ LIBS ?=
4042
41- # Show console window on Windows? (set to false for GUI-only apps) (Windows)
43+ # Show console window on Windows? (set to false for GUI-only apps)
4244ifeq ($(USE_CONSOLE ) ,false)
4345 LDFLAGS += -mwindows
44- # LDFLAGS += -luser32 -lgdi32
4546endif
4647
48+ # ─── Platform detection ───────────────────────────────────────────────────────
49+
50+ UNAME_S := $(shell uname -s 2>/dev/null || echo Unknown)
51+
52+ RM := rm -rf
53+ ifeq ($(findstring Windows,$(OS ) ) ,Windows)
54+ IS_WINDOWS := yes
55+ MKDIR := mkdir
56+ EXE_EXT := .exe
57+ else ifeq ($(UNAME_S),Darwin)
58+ IS_MACOS := yes
59+ MKDIR := mkdir -p
60+ EXE_EXT :=
61+ else
62+ IS_LINUX := yes
63+ MKDIR := mkdir -p
64+ EXE_EXT :=
65+ endif
66+
67+ TARGET := $(APP_NAME )$(EXE_EXT )
68+
4769# ─── Automatic source & object discovery ──────────────────────────────────────
4870
4971# Find all source files recursively
@@ -58,70 +80,114 @@ OBJECTS := $(patsubst %.$(SRC_EXT),$(OBJ_DIR)/%.o,$(SOURCES))
5880DEPENDENCIES := $(OBJECTS:.o=.d )
5981
6082INCLUDES := $(addprefix -I,$(INCLUDE_DIRS ) )
61- LIB_DIRS ?= -L./lib
62- LIBS ?=
6383
64- LDFLAGS += $(LIB_DIRS ) $(addprefix -l,$(LIBS ) )
65-
66- # Generate files that encode make rules for the .h dependencies
84+ # Generate files that encode make rules for header dependencies
6785DEPFLAGS = -MT $@ -MMD -MP -MF $(DEP_DIR ) /$* .d
6886
6987# ─── Build rules ──────────────────────────────────────────────────────────────
7088
71- .PHONY : all dirs
89+ .PHONY : all dirs clean clean-banner run debug release help info
7290
73- all : clean-banner dirs $(BIN_DIR ) /$(APP_NAME )
91+ all : clean-banner dirs $(BIN_DIR ) /$(TARGET )
7492
7593dirs :
76- @mkdir -p $(BIN_DIR ) $(OBJ_DIR ) $(DEP_DIR )
77-
78- $(OBJ_DIR ) /% .o : % .$(SRC_EXT ) | dirs
79- @printf " [Compiling] -> %s\n" " $<"
80- @mkdir -p $(@D ) $(dir $(DEP_DIR ) /$* .d) 2> /dev/null || true
81- @$(CXX ) $(CXXFLAGS ) $(INCLUDES ) $(DEPFLAGS ) -c $< -o $@ 2> compile.log || \
82- { printf " \n[ERROR] Compilation failed for $<\n" ; cat compile.log; rm -f compile.log; exit 1; }
83- @rm -f compile.log
84-
85- $(BIN_DIR ) /$(APP_NAME ) : $(OBJECTS )
86- @printf " \n─── Linking → %s\n" " $@ "
87- @$(CXX ) $^ -o $@ $(LDFLAGS ) && \
88- printf " %-12s: Linked successfully\n" " Status" || \
89- { printf " %-12s: Linking failed\n" " Status" ; exit 1; }
90-
91- $(DEP_DIR ) /% .d : ;
92- .PRECIOUS : $(DEP_DIR ) /% .d
93-
94- -include $(DEPENDENCIES )
95-
96- # ─── Build variants ───────────────────────────────────────────────────────
97-
98- .PHONY : debug release
94+ @$(MKDIR ) " $( BIN_DIR) " 2> /dev/null || true
95+ @$(MKDIR ) " $( OBJ_DIR) " 2> /dev/null || true
96+ @$(MKDIR ) " $( DEP_DIR) " 2> /dev/null || true
97+ @mkdir -p " $( DEP_DIR) " 2> /dev/null || true
98+
99+ $(OBJ_DIR ) /% .o : % .$(SRC_EXT )
100+ @printf " [Compiling] → %s\n" " $<"
101+ @mkdir -p " $( @D) "
102+ @mkdir -p " $( DEP_DIR) /$( dir $* ) "
103+ @if $(CXX ) $(CXXFLAGS ) $(INCLUDES ) $(DEPFLAGS ) -c $< -o $@ ; then \
104+ printf " ✓ Success\n" ; \
105+ else \
106+ printf " ✗ Error\n" ; \
107+ exit 1; \
108+ fi
109+
110+ $(BIN_DIR ) /$(TARGET ) : $(OBJECTS )
111+ @printf " \n───────── Linking\n"
112+ @printf " %-15s: %s\n" " Target" " $( TARGET) "
113+ @printf " %-15s: %s\n" " Objects" " $( words $( OBJECTS) ) "
114+ @if $(CXX ) $^ -o $@ $(LDFLAGS ) $(LIBS ) ; then \
115+ printf " ✓ Linked successfully\n" ; \
116+ else \
117+ printf " ✗ Linking failed\n" ; \
118+ exit 1; \
119+ fi
120+
121+ # Only include existing dependency files - avoids infinite loops
122+ -include $(wildcard $(DEPENDENCIES ) )
123+
124+ # ─── Build variants ───────────────────────────────────────────────────────────
125+
126+ # Address and Undefined Behavior Sanitizers (only on non-Windows)
127+ SANITIZERS :=
128+ ifneq ($(OS ) ,Windows_NT)
129+ SANITIZERS := -fsanitize=address,undefined
130+ endif
99131
100- debug : CXXFLAGS += -Og -g -ggdb3 -DDEBUG
132+ debug : CXXFLAGS += -Og -ggdb3 -DDEBUG
133+ debug : LDFLAGS += $(SANITIZERS )
101134debug : all
102135
103136release : CXXFLAGS += -O3 -DNDEBUG -march=native
104137release : all
105138
106- # ─── Additional targets ──────────────────────────────────────────────────────
107-
108- .PHONY : clean-banner run clean help
139+ # ─── Display targets ──────────────────────────────────────────────────────────
109140
110141clean-banner :
111- @if [ -t 1 ]; then clear; fi
142+ @cls 2> /dev/null || clear
143+ @printf " \n═══════════════════════════════════════════\n"
144+ @printf " Building: $( APP_NAME) \n"
145+ @printf " ═══════════════════════════════════════════\n\n"
112146
113147run : release
114- @$(BIN_DIR ) /$(APP_NAME )
148+ @printf " \n───────── Execution\n"
149+ @$(BIN_DIR ) /$(TARGET )
150+
151+ # ─── Cleanup targets ──────────────────────────────────────────────────────────
115152
116153clean :
117- @rm -rf $(BUILD_BASE )
118- @printf " Cleaned build directory\n"
154+ @printf " \n───────── Cleaning\n"
155+ @$(RM ) " $( OBJ_DIR) " 2> /dev/null || true
156+ @$(RM ) " $( DEP_DIR) " 2> /dev/null || true
157+ @$(RM ) " $( BIN_DIR) /$( TARGET) " 2> /dev/null || true
158+ @printf " ✓ Cleaned build artifacts\n"
159+
160+ full-clean :
161+ @printf " \n───────── Full Clean\n"
162+ @$(RM ) " $( BUILD_BASE) " 2> /dev/null || true
163+ @printf " ✓ Removed build directory\n"
164+
165+ # ─── Info targets ─────────────────────────────────────────────────────────────
119166
120167help :
121- @echo " Available targets:"
122- @echo " make [all] - Build (default)"
123- @echo " make debug - Build with debug symbols"
124- @echo " make release - Build optimized"
125- @echo " make run - Build release + execute"
126- @echo " make clean - Remove build artifacts"
127- @echo " make help - Show this help"
168+ @printf " \n═══════ C++ Build System ═══════\n"
169+ @printf " Usage: make [target] [VAR=value]\n\n"
170+ @printf " Targets:\n"
171+ @printf " all Build project (default)\n"
172+ @printf " debug Debug build + sanitizers\n"
173+ @printf " release Optimized release build\n"
174+ @printf " run Build & execute\n"
175+ @printf " clean Remove objects & binary\n"
176+ @printf " full-clean Delete entire build/\n"
177+ @printf " info Show configuration\n"
178+ @printf " help This message\n\n"
179+ @printf " Variables (example: make APP_NAME=MyApp):\n"
180+ @printf " APP_NAME App name (default: $( APP_NAME) )\n"
181+ @printf " CXX Compiler (default: $( CXX) )\n"
182+ @printf " LANGUAGE C++ standard (default: $( LANGUAGE) )\n\n"
183+
184+ info :
185+ @printf " \n═══════ Project Info ═══════\n"
186+ @printf " App Name : $( APP_NAME) \n"
187+ @printf " Target : $( TARGET) \n"
188+ @printf " Compiler : $( CXX) \n"
189+ @printf " C++ Standard : $( LANGUAGE) \n"
190+ @printf " Sources : $( words $( SOURCES) ) \n"
191+ @printf " Source Dirs : $( SOURCE_DIRS) \n"
192+ @printf " Include Dirs : $( INCLUDE_DIRS) \n"
193+ @printf " Build Base : $( BUILD_BASE) \n\n"
0 commit comments