GNU Make 實戰教程:規則、變量、函數、隱含規則全覆蓋
Makefile 定義構建依賴關係,實現增量編譯。本文從基礎語法到進階技巧,系統梳理 Makefile 核心知識體系。
核心規則語法
target: prerequisites
command # 必須以 Tab 開頭
target:目標文件/標簽
prerequisites:依賴文件
command:Shell 命令
經典範例:8 源文件項目
objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o
edit: $(objects)
cc -o edit $(objects)
main.o: defs.h
kbd.o: defs.h command.h
command.o: defs.h command.h
display.o: defs.h buffer.h
insert.o: defs.h buffer.h
search.o: defs.h buffer.h
files.o: defs.h buffer.h command.h
utils.o: defs.h
.PHONY: clean
clean:
rm -f edit $(objects)
關鍵進階特性
1. 變量與賦值運算符
| 運算符 | 行為 | 示例 |
= | 遞歸展開(延遲求值) | CFLAGS = $(INCLUDES) -O2 |
:= | 即時展開(立即求值) | OBJS := $(wildcard *.o) |
?= | 條件賦值(未定義時) | CC ?= gcc |
+= | 追加 | CFLAGS += -Wall |
2. 自動化變量
$@ 目標文件名
$< 第一個依賴文件
$^ 所有依賴文件(去重)
$+ 所有依賴文件(保留重複)
$? 比目標新的依賴文件
$* 目標幹名(%匹配部分)
3. 模式規則與靜態模式
# 模式規則:通用編譯規則
%.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
# 靜態模式:限定特定目標集
objects = foo.o bar.o
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
4. 常用函數
| 函數 | 用法示例 | 說明 |
wildcard | $(wildcard *.c) | 文件通配展開 |
patsubst | $(patsubst %.c,%.o,$(SRCS)) | 模式替換 |
subst | $(subst .c,.o,$(var)) | 字符串替換 |
filter | $(filter %.o,$(files)) | 模式過濾 |
foreach | $(foreach f,$(files),$(f).bak) | 循環展開 |
if | $(if $(DEBUG),-g,-O2) | 條件表達式 |
shell | $(shell date) | 執行 Shell 命令 |
5. 自動生成依賴關係
# 生成 .d 文件規則
%.d: %.c
@set -e; rm -f $@; \
$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
# 包含所有 .d
sources = foo.c bar.c
include $(sources:.c=.d)
6. 偽目標與特殊目標
.PHONY: clean:聲明偽目標,避免與同名文件衝突
.INTERMEDIATE:聲明中間文件,構建後自動刪除
.SECONDARY:保留中間文件
.PRECIOUS:防止中斷時刪除目標
.SUFFIXES:後綴列表(舊式隱含規則)
7. 命令控制前綴
| 前綴 | 效果 |
@ | 不回顯命令(常用於 @echo) |
- | 忽略錯誤繼續執行 |
+ | 即使 -n/-q/-t 也執行 |
常用 make 參數
-f file 指定 Makefile
-j N 並行 N 槽構建
-n 僅打印命令不執行
-k 出錯繼續
-C dir 切換目錄執行
-p 打印內部數據庫
-q 問題模式(退出碼指示是否需更新)
最佳實踐清單
- 變量統一管理編譯器/標誌/路徑
- 使用
wildcard/patsubst 自動收集源文件
- 啟用
-MM 自動生成頭文件依賴
clean 放最後,加 .PHONY 和 - 前綴
- 大項目拆分子目錄 Makefile,用
$(MAKE) -C subdir 遞歸構建
- 導出變量用
export,隔離用 unexport
調試技巧
make -p -f /dev/null 查看內建規則/變量
make -d 詳細調試輸出
make -n 乾運行檢查命令序列