據(jù)說(shuō)從事嵌入式系統(tǒng)開(kāi)發(fā)的, 如果不能駕馭好 Makefile, 會(huì)很難做到游刃有余. 看到這句話, 不禁讓我涼了好一陣.
一直以來(lái), 都是在別人搭建好的平臺(tái)上做應(yīng)用, 即使有時(shí)需要自己動(dòng)手來(lái)寫(xiě), 也只是寫(xiě)些特別簡(jiǎn)單的. 今天就想認(rèn)真的學(xué)習(xí)下 Makefile.
概念
學(xué)習(xí) Makefile 需要掌握兩個(gè)重要的概念, 一個(gè)是目標(biāo)(target), 還有一個(gè)是依賴(dependency)
規(guī)則
# 規(guī)則語(yǔ)法
targets : prerequisites
command
...(可以有多個(gè)命令)
1. 命令前面必須只有 Tab 鍵, 目標(biāo)和依賴的格式為 target:dependency
, 置于命令前面蚂斤。
# makefile
# all:
# echo "Hello world!"
[root@ ~]$ make
echo "Hello world!"
Hello world!
在這里存捺,all 是目標(biāo),沒(méi)有依賴曙蒸“浦危可以運(yùn)行 make
或者 make all
。
- 一個(gè) Makefile 中可以定義多個(gè)目標(biāo)纽窟。
- 調(diào)用 make 命令時(shí)肖油,我們得告訴它我們的目標(biāo)是什么,即要它干什么臂港。當(dāng)沒(méi)有指明具體的目標(biāo)是什么時(shí)森枪,那么 make 以 Makefile 文件中定義的第一個(gè)目標(biāo)作為這次運(yùn)行的目標(biāo)。這“第一個(gè)”目標(biāo)也稱之為默認(rèn)目標(biāo)审孽。
- 當(dāng) make 得到目標(biāo)后县袱,先找到定義目標(biāo)的規(guī)則,然后運(yùn)行規(guī)則中的命令來(lái)達(dá)到構(gòu)建目標(biāo)的目的佑力。規(guī)則可以有多條式散。
2. 上面的例子太簡(jiǎn)單了,沒(méi)用到依賴搓萧。下面增加一個(gè)依賴(在命令前面加 @ 可以屏蔽命令的顯示)
[root@ ~]$ cat makefile
all: test
@echo "Hello world!"
test:
@echo "I am test!"
[root@ ~]$ make test
I am test!
[root@ ~]$ make
I am test!
Hello world!
這里杂数,添加了 test 作為 all 的依賴宛畦,在 make
或者 make all
時(shí)瘸洛,make 將先檢查 all:后面的依賴 test,再找到目標(biāo) test次和,先執(zhí)行 echo “I am test反肋!”
,然后再回到 all 規(guī)則執(zhí)行下面的命令 echo “Hello world踏施!”
要點(diǎn)
1. 命令前面必須只有 Tab 鍵
2. := 簡(jiǎn)單擴(kuò)展變量, 對(duì)變量只進(jìn)行一次掃描和替換
x = val_1
y := $(x) test
x = val_2
.PHONY: all
all:
@echo "x = $(x), y = $(y)"
# 輸出
# x = val_2, y = val_1 test
3. ?= 條件賦值, 當(dāng)變量以前沒(méi)有定義時(shí),就定義它并且將左邊的值賦值給
它,如果已經(jīng)定義了那么就不再改變其值
x = val
x ?= test
y ?= test
.PHONY: all
all:
@echo "x = $(x), y = $(y)"
# 輸出
# x = val, y = test
4. = 遞歸擴(kuò)展變量, 與簡(jiǎn)單擴(kuò)展變量不同的是, 會(huì)找到變量最后一次賦的值
x = val_1
y = $(x) test
x = val_2
.PHONY: all
all:
@echo "x = $(x), y = $(y)"
# 輸出
# x = val_2, y = val_2 test
5. 自動(dòng)變量
a. $@ 表示一個(gè)規(guī)則的目標(biāo), 當(dāng)有多個(gè)目標(biāo)時(shí), $@所指的是其中任何造成命令被運(yùn)行的目標(biāo)
b. $^ 表示規(guī)則中的所有先決條件
c. $< 表示規(guī)則中的第一個(gè)先決條件
.PHONY: all
all: 1st 2nd 3rd
@echo "\$$@ = $@"
@echo "\$$^ = $^"
@echo "\$$< = $<"
1st 2nd 3rd:
[taylorpc@ test02]$ make
$@ = all
$^ = 1st 2nd 3rd
$< = 1st
6. 特殊變量
a. MAKE, 表示 make 的命令是什么
b. MAKECMDGOALS, 表示 make 的目標(biāo)是什么
PHONY: all
all:
@echo "MAKE = $(MAKE)"
@echo "MAKECMDGOALS = $(MAKECMDGOALS)"
[taylorpc@ test02]$ make
MAKE = make
MAKECMDGOALS =
[taylorpc@ test02]$ make all
MAKE = make
MAKECMDGOALS = all
7. 變量與值的來(lái)源
a. 自動(dòng)變量, 是在每一個(gè)規(guī)則中根據(jù)上下文自動(dòng)獲取的
b. 可以在 make 時(shí)定義, 如 `make value=99`, 這樣子當(dāng) `echo $(value)` 時(shí)輸出的就是 99 了.
c. 可以從 shell 環(huán)境中獲得, 如 `export test=val`
d. 還可以在 makefile 直接賦值, 如 "=", "+="
8. 高級(jí)變量引用 (或 patsubst): 在賦值的同時(shí)完成后綴替換
.PHONY: all
src = a.o \
b.o \
c.o
dst = $(src:.o=.c)
all:
@echo "dst = $(dst)"
[taylorpc@ test03]$ make
dst = a.c b.c c.c
9. override 指令: 覆蓋用戶自定義的變量 (上面第 7 點(diǎn)的 b 小點(diǎn))
.PHONY: all
override test = 0
all:
@echo $(test)
$ make test=9999
# output: 0
10. 模式: 型如 %.o:%.c
這樣做的好處是, 當(dāng)需要編譯多個(gè)相同類型的文件時(shí), 不需要每個(gè)文件都編寫(xiě)一個(gè)對(duì)應(yīng)的規(guī)則, 只需要下面這一條就可以了:
%.o: %.c
$(CC) -o $@ -c $^
11. 函數(shù)(wildcard, patsubst)
a. wildcard: 擴(kuò)展通配符
b. notdir: 去除路徑
c. patsubst: 替換通配符
* 這一點(diǎn)應(yīng)該是在第 10 小點(diǎn)的模式之前使用, 這樣方便列出所有源文件和依賴文件
src = $(wildcard ./*.c ./sub/*.c) # 獲取當(dāng)前目錄下和 sub 目錄下的所有 .c 文件, 展開(kāi)并以空格分隔
nodir = $(notdir $(src)) # 去除路徑
obj = $(patsubst %.c, %.o, $(nodir)) # 將所有的 .c 替換成 .o
all:
@echo "src: $(src)"
@echo "nodir: $(nodir)"
@echo "obj: $(obj)"
# output
src: ./test.c ./sub/test2.c ./sub/test3.c
nodir: test.c test2.c test3.c
obj: test.o test2.o test3.o
12. 函數(shù) (addprefix 在字符串前添加前綴)
[taylorpc@ test03]$ cat makefile
.PHONY: all
src = test1.c \
test2.c \
test3.c
src_dir = $(addprefix myprefix/, $(src))
all:
@echo "src: $(src)"
@echo "src_dir: $(src_dir)"
[taylorpc@ test03]$ make
src: test1.c test2.c test3.c
src_dir: myprefix/test1.c myprefix/test2.c myprefix/test3.c
13. 函數(shù) (filter 過(guò)濾, 獲取想要的內(nèi)容/文件)
.PHONY: all
src = test.c test.o test.h value.c value.h
res = $(filter %.c %.h, $(src))
all:
@echo "res: $(res)"
$ make # output
src: test.c test.o test.h value.c value.h
res: test.c test.h value.c value.h
14. 函數(shù) (filter-out 過(guò)濾, 濾除不想要的內(nèi)容)
.PHONY: all
src = main.c main.o test.c test.o test.h
res = $(filter-out main%c %.o, $(src))
all:
@echo "src: $(src)"
@echo "res: $(res)"
# output
src: main.c main.o test.c test.o test.h
res: test.c test.h
15. 函數(shù) (strip 去除多余空格)
.PHONY: all
src = test.c ok.h data.dat
res = $(strip $(src))
all:
@echo "src = $(src)"
@echo "res = $(res)"
# output
src = test.c ok.h data.dat
res = test.c ok.h data.dat
[1] 至簡(jiǎn)李云. 駕馭Makefile(準(zhǔn)完整版) 2009.08.25