#1 make是一個命令,他會按照自己的規則執行名字爲Makefile、makefile或者之類的名字,或者通過 make -f 1.txt 這樣來指定執行一個文件。
#2 make命令解析文件的最基本、最重要的途徑就是如下格式:
<target> : <prerequisites>
[tab] <commands>
對上面這兩行代碼的解讀:
1 - 想要得到target,材料是prerequisites,工具是commands。
2 - target是必須的,prerequisites和commands至少要有一個存在。
3 - target可以有多個,像prerequisites一樣,多個目標之間用空格分割。
#3 注意:Makefile什麼都不是,我們面向的應該是make這個命令是如何使用的,Makefile只是按照make命令要求寫的一個標準格式文件。
#4 僞目標(用來指定非編譯動作,因爲正常情況下,make動作都會輸出目標文件,如果我想做某個動作而不是輸出目標文件,就要指定目標動作爲僞目標)
clean:
rm -rf *
make動作是針對Makefile(或者-f指定一個文件)中的“目標”而言的,如果不指定,那麼就取“第一個目標”,如果指定,則取指定的目標。
針對上面這種情況,有一個BUG,如果當前目錄中有一個叫做clean的文件,那麼make就會以爲下面的命令行是用來生成clean文件的,所以不會再去執行。針對這種情況,
需要把clean明確指定爲僞目標: .PHONY:clean
clean:
rm -rf *
#5 前置條件(材料)
<target> : <prerequisites>
[tab] <commands>
只要前置條件列表和之前不一樣了,或者裏面的內容發生更新了,那麼就使用commands重新構建target。
注:如果某個target後面沒有前置條件,那麼每次執行make <target>,commands都一定會執行。
#6 再說僞目標
有時候也可以這樣用:當commands是空的時候,僞目標類似宏定義,比如 all:1.c 2.c 3.c ,此時make或者make all,相當於make 1.c ,make 2.c , make 3.c
會依次執行all所指代的前置條件。
注:這也是幾乎所有Makefile都在用的一點,需要輸出多個目標的時候,就先定一個總的來代替多個目標
#7 命令
命令用來表示如何生成target,命令有一行或者多行“shell命令”組成。
默認情況下命令前面要有TAB鍵,如果想換成別的,可以設置環境變量.RECIPEPREFIX,比如.RECIPEPREFIX = >
all:
> echo Hello, world
#8 “命令”注意要點
命令可以有多行,但是不同於shell腳本,這多行是由多個進程一起執行的,所以相互之間沒有關聯。比如:
all:
export a=1
echo $a
針對上面這個文件,做make或者make all,無法正確獲得a的值。
可以用如下幾種方法來解決:
1 - 命令放在一行,用分號隔開
all:
export a=1;echo $a
2 - 命令放在不同的行,用\連接
all:
export a=1 \
echo $a
3 - 通過僞目標標註
.ONESHELL:
all:
export a=1
echo $a
#9 語法
#9-1 “回聲”
默認情況下,會向標準輸出打印每一條command。即使是以#開頭,都會打印(但是前置TAB不可少,少了就不是command了)。這叫做“回聲”
如果想關閉,只需要在command前面加一個@就行了。
實際工作過程中,一般會給command的註釋前面加上@
#9-2 “通配符”
和bash的通配符使用一樣,*,?,[1-2]等
#9-3 “模式匹配”
%.o: %.c代表對當前目錄下所有.c文件做.o依賴,比如當前目錄下有1.c和2.c,那麼以上的語句等於:
1.o:1.c
2.o:2.c
#9-4 “變量和賦值”
有四種賦值方式:
1 - VARIABLE = value # 在執行時擴展,允許遞歸擴展
2 - VARIABLE := value # 在定義時擴展
3 - VARIABLE ?= value # 只有在該變量爲空時才設置值
4 - VARIABLE += value # 將值追加到變量的尾端
#9-5 “內置變量”
提供了一些默認的環境變量,比如$(CC) 指向當前使用的編譯器,$(MAKE) 指向當前使用的Make工具。
更多見https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html
#9-6 “自動變量”
$@ - 當前commands對應的target
$< - 第一個prerequisites
$? - 較當前target時間點而言,所有更新過的prerequisites(比較有用,可以用來取到所有近期變動過的prerequisites)
$^ - 指代所有的prerequisites
$* - 所有%匹配的文件名,無後綴(比如前面的 %o:%.c,在這個依賴關係的commands中使用$*,就指代所有的文件名,比如上例中的1 2)
$(@D)和$(@F) - $(@D)指$@的路徑,$(@F)指$@的文件名
$(<D)和$(<F) - $(<D)指$<的路徑,$(<F)指$<的文件名
#9-7 “循環和判斷”
語法同bash
#9-8 “函數”
有許多內置函數可在整個Makefile內使用(不侷限於target、prerequisites和commands,比如在做變量賦值時也可以用)
格式爲: $(function arguments)
# 或者
${function arguments}
1 - shell函數(執行一個shell命令)
例如 srcfiles := $(shell echo src/{00..99}.txt)
2 - wildcard函數(用來在 Makefile 中,替換 Bash 的通配符 )
例如 srcfiles := $(wildcard src/*.txt)
3 - subst函數(用來文本替換)
例如 將字符串"feet on the street"替換成"fEEt on the strEEt"
$(subst ee,EE,feet on the street)
4 - patsubst函數(用於模式匹配的替換)
例如 將文件名"x.c.c bar.c",替換成"x.c.o bar.o"
$(patsubst %.c,%.o,x.c.c bar.c)
5 - (!!!常用!!!)替換後綴名
例如 min:$(*.pc:=.c),把所有的pc結尾的文件,替換成c結尾
#10 ----------------------終-----------------------