一個簡單的Makefile編譯所有c代碼文件爲每個單獨程序
筆者初學Makefile
用來方便編譯項目,記錄一下,若有問題歡迎指正,文件內容附在文末
本文目的
我在./src/
目錄下有若干.c
文件,想對每個文件均進行編譯,中間代碼文件*.o
存放在./build/obj/
下,目標可執行文件放在./build/
下
Makefile的工作流程
- 沒有指定輸出項目時,Makefile會先在所有目標中找到第一個沒有通配符的目標進行構造;例如本文中的
all
,即時它是個僞目標 - 根據構造
all
的規則,需要構造$(BUILD)
,而$(BUILD)
即是$(BUILD_DIR)
下無後綴的可執行文件 - 於是要構造的目標就變爲了
$(OBJ_DIR)/%.o
,然後make在規則中繼續尋找,找到了一個匹配的規則$(BUILD_DIR)/%: $(OBJ_DIR)/%.o
,但不幸的是該規則依賴OBJS := $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
,於是繼續尋找 - 下面又找到了
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
,現在不需要繼續尋找了,即執行這個規則下的語句進行編譯但不鏈接 - 完成後回到上層進行對
.o
文件的鏈接,然後繼續回到上層,重複這個過程使得對於每一個$(BUILD)
中的目標都得到了生成
不刪除中間文件
上述過程會在全部編譯完成後使用rm
命令刪除中間過程文件,僅保留目標文件,可以通過添加一條
.SECONDARY: $(OBJS)
讓$(OBJS)
成爲第二目標,從而不被清理掉
編寫clean
方法
我們有時需要對項目進行清理,此時只需要將clean
寫進僞目標,然後把它的實現放到最後一個就好了,實現很簡單,即使用rm
對編譯過程文件和結果文件進行清理即可
一個比較建議的項目樹組織
.
├── build
│ ├── 若干可執行文件
│ └── obj
│ └── 若干.o中間代碼文件
├── LICENSE
├── Makefile
├── README.md
└── src
└── 若干c源文件
附:Makefile全文
# File paths
SRC_DIR := ./src
BUILD_DIR := ./build
OBJ_DIR := $(BUILD_DIR)/obj
# Compilation flags
CC := gcc
LD := gcc
CFLAGS := -Wall
# Files to be compiled
SRCS := $(wildcard $(SRC_DIR)/*.c)
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
BUILD := $(OBJS:$(OBJ_DIR)/%.o=$(BUILD_DIR)/%)
# Don't remove *.o files automatically
.SECONDARY: $(OBJS)
all: $(BUILD)
# Compile each *.c file as *.o files
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
@echo + CC $<
@mkdir -p $(OBJ_DIR)
@$(CC) $(CFLAGS) -c -o $@ $<
# Link each *.o file as executable files
$(BUILD_DIR)/%: $(OBJ_DIR)/%.o
@echo + LD $@
@mkdir -p $(BUILD_DIR)
@$(LD) $(CFLAGS) -o $@ $<
.PHONY: all clean
clean:
rm -rf $(BUILD_DIR)