gcc -MM 生成 .d 文件,精確追蹤 .c/.cpp 對頭文件的依賴,修改頭文件自動觸發相關源文件重編譯。DEBUG=YES 時啟用 -g -O0 -Wall -pg 等調試標誌,輸出至 bin/debug/、obj/debug/;否則 Release 模式 -O3,輸出至 bin/release/。project/ ├── src/ # 源文件 (.c, .cpp) ├── inc/ # 頭文件 (可選,已包含在 INC_PATH) ├── obj/debug|release/ # 中間 .o 文件 ├── dep/ # 依賴 .d 文件 ├── bin/debug|release/ # 最終可執行文件 └── lib/ # 靜態庫
# 編譯器 CC = gcc CXX = g++ LD = g++ AR = ar rc # 路徑 HOME_PATH = $(realpath .) SOURCE_PATH = $(HOME_PATH)/src INC_PATH = -I$(HOME_PATH)/src DEP_PATH = $(HOME_PATH)/dep LIB_PATH = -L$(HOME_PATH)/lib # 源文件自動收集 SRCS = $(wildcard $(SOURCE_PATH)/*.c) $(wildcard $(SOURCE_PATH)/*.cpp) # 目標文件與依賴文件映射 OBJS = $(patsubst %, $(OBJ_PATH)/%.o, $(basename $(notdir $(SRCS)))) DEPS = $(patsubst %, $(DEP_PATH)/%.d, $(basename $(notdir $(SRCS)))) # 編譯標誌 DEBUG_CFLAGS = -g -O0 -Wall -Wconversion -Wuninitialized -D_DEBUG -m64 -pg RELEASE_CFLAGS = -O3 -m64 # ... CXXFLAGS, LDFLAGS 同理 # 連接庫 LIBS = -Wl,-dn -lev -Wl,-dn -lglog -Wl,-dn -lpthread
$(DEP_PATH)/%.d : $(SOURCE_PATH)/%.c @set -e; \ rm -f $@; \ $(CC) -MM $(CFLAGS) $(INC_PATH) $< > $@.tmp; \ sed 's,\($*\)\.o[ :]*,$(OBJ_PATH)/\1.o $@ : ,g' < $@.tmp > $@; \ rm -f $@.tmp $(DEP_PATH)/%.d : $(SOURCE_PATH)/%.cpp @set -e; \ rm -f $@; \ $(CC) -MM $(CFLAGS) $(INC_PATH) $< > $@.tmp; \ sed 's,\($*\)\.o[ :]*,$(OBJ_PATH)/\1.o $@ : ,g' < $@.tmp > $@; \ rm -f $@.tmp -include $(DEPS)
sed 將 gcc -MM 輸出的 foo.o: foo.c bar.h 重寫為 obj/debug/foo.o dep/foo.d: foo.c bar.h,確保 .d 文件本身也納入依賴鏈。
$(OBJ_PATH)/%.o : $(SOURCE_PATH)/%.c $(CC) -c $(CFLAGS) $(INC_PATH) $< -o $(OBJ_PATH)/$(basename $(notdir $@)).o $(OBJ_PATH)/%.o : $(SOURCE_PATH)/%.cpp $(CXX) -c $(CXXFLAGS) $(INC_PATH) $< -o $(OBJ_PATH)/$(basename $(notdir $@)).o
src/,頭文件可置於 src/ 或 inc/(需補充 INC_PATH)。make DEBUG=YES 構建調試版;make 構建發布版。make clean 清理所有中間產物。mkdir -p、sed 等命令。