make工程管理器
由成百上千個(gè)文件構(gòu)成的項(xiàng)目,如果其中只有一個(gè)或少數(shù)幾個(gè)文件進(jìn)行了修改,按照之前所學(xué)的gcc編譯工具,就不得不把這所有的文件重新編譯一遍,因?yàn)榫幾g器并不知道哪些文件是最近更新的
所以人們就希望有一個(gè)工程管理器能夠自動(dòng)識(shí)別更新了的文件代碼
實(shí)際上,make工程管理器也就是個(gè)“自動(dòng)編譯管理器”,這里的自動(dòng)是指它能夠根據(jù)文件時(shí)間戳自動(dòng)發(fā)現(xiàn)更新過(guò)的文件而減少編譯的工作量,同時(shí),它通過(guò)讀入makefile文件的內(nèi)容來(lái)執(zhí)行大量的編譯工作。用戶只需編寫(xiě)一次簡(jiǎn)單的編譯語(yǔ)句就可以了。
## makefile基本結(jié)構(gòu)
makefile是make讀入的惟一配置文件,因此下面講述makefile的編寫(xiě)規(guī)則。在一個(gè)makefile中通常包含如下內(nèi)容:
?- 需要由make工具創(chuàng)建的目標(biāo)體(target),通常是目標(biāo)文件或可執(zhí)行文件;
?- 要?jiǎng)?chuàng)建的目標(biāo)體所依賴的文件(dependency_file)
?- 創(chuàng)建每個(gè)目標(biāo)體時(shí)需要運(yùn)行的命令(command),這一行必須以制表符(Tab鍵)開(kāi)頭
?它的格式為
?target : dependency_files
? command /*該行必須以Tab鍵開(kāi)頭*/
例如,有兩個(gè)文件分別為hello.c和hello.h,創(chuàng)建的目標(biāo)體為hello.o,執(zhí)行的命令為gcc編譯指令:gcc -c hello.c ,那么,對(duì)應(yīng)的makefile就可以寫(xiě)為:
#The simplest example
hello.o : hello.c? ? hello.h
gcc -c hello.c -o hello.o
接著就可以使用make了。使用make的格式為:make target ,這樣make 就會(huì)自動(dòng)讀入makefile(也可以是首字母大寫(xiě)的Makefile)并執(zhí)行對(duì)應(yīng)target的command語(yǔ)句,并會(huì)找到相應(yīng)的依賴文件。如下所示:
[root@localhost makefile]# **make hello.o**
**gcc -c hello.c -o hello.o**
[root@localhost makefile]# ls
hello.c hello.h **hello.o** makefile
可以看到,makefile執(zhí)行了“hello.o”對(duì)應(yīng)的命令語(yǔ)句,并生成了“hello.o”目標(biāo)體
**注意:在makefile中的每一個(gè)command前必須有“Tab符”,否則在運(yùn)行make命令時(shí)會(huì)出錯(cuò)。**
**makefile變量**
上面示例的makefile在實(shí)際中是幾乎不存在的,因?yàn)樗^(guò)于簡(jiǎn)單,僅包含兩個(gè)文件和一個(gè)命令,在這種情況下完全不必要編寫(xiě)makefile而只需在shell中直接輸入即可,在實(shí)際中使用的makefile往往是包含很多的文件和命令的,這也是makefile產(chǎn)生的原因。下面就給出稍微復(fù)雜一些的makefile講解。
```c
david : kang.o yul.o
gcc kang.o bar.o -o myprog
kang.o : kang.c kang.h head.h
gcc -Wall -O -g -c kang.c -o kang.o
yul.o : bar.c head.h
gcc -Wall -O -g -c yul.c -o yul.o
```
在這個(gè)makefile中有3個(gè)目標(biāo)體(target),分別為david、kang.o 、yul.o,其中第一個(gè)目標(biāo)體的依賴文件就是后兩個(gè)目標(biāo)體。如果用戶使用命令“make david”,則make管理器就是找到david目標(biāo)體開(kāi)始執(zhí)行。
這時(shí),make會(huì)自動(dòng)檢查相關(guān)文件的時(shí)間戳。首先,在檢查“kang.o”、“yul.o”和“david”3個(gè)文件的時(shí)間戳之前,它會(huì)向下查找那些把“kang.o”或“yul.o”作為目標(biāo)文件的時(shí)間戳。比如,“kang.o”的依賴文件為“kang.c”、“kang.h”、“head.h”。如果這些文件中任何一個(gè)的時(shí)間戳比“kang.o”新,則命令”gcc -Wall -O -g -c kang.c -o kang.o“將會(huì)執(zhí)行,從而更新文件”kang.o“。在更新完”kang.o“或”yul.o“之后,make會(huì)檢查最初的”kang.o“、”yul.o“和”david“3個(gè)文件,只要文件”kang.o“或”yul.o“中的至少有一個(gè)文件的時(shí)間戳比”david“新,則第二行命令就會(huì)被執(zhí)行。這樣,make就完成了自動(dòng)檢查時(shí)間戳的工作,開(kāi)始執(zhí)行編譯工作。這也就是make工作的基本流程。
接下來(lái),為了進(jìn)一步簡(jiǎn)化編輯和維護(hù)makefile,make允許在makefile中創(chuàng)建和使用變量。**變量是在makefile中定義的名字,用來(lái)代替一個(gè)文本字符串,該文本字符串稱為該變量的值。**
**在makefile中的變量定義有兩種方式:一種是遞歸展開(kāi)方式,另一種是簡(jiǎn)單方式。**
遞歸展開(kāi)方式定義的變量是在引用該變量時(shí)進(jìn)行替換的,即如果該變量包含了對(duì)其他變量的引用,則在引用該變量時(shí)一次性將內(nèi)嵌的變量全部展開(kāi),雖然這種類(lèi)型的變量能夠很好地完成用戶的指令,但是它也有嚴(yán)重的缺點(diǎn),如不能在變量后追加內(nèi)容(因?yàn)檎Z(yǔ)句CFLAGS:=$(CFLAGS) -O在變量擴(kuò)展過(guò)程中可能導(dǎo)致無(wú)窮循環(huán))。~~但是我并沒(méi)有看出這個(gè)語(yǔ)句是怎么在變量后追加內(nèi)容的。莫非它的意思是嵌套定義自己就是在變量后追加內(nèi)容?~~?
為了避免上述問(wèn)題,簡(jiǎn)單擴(kuò)展型變量的值在定義處展開(kāi),并且只展開(kāi)一次,因此,它不包含任何對(duì)其他變量的引用,從而消除變量的嵌套引用。~~讀到這,可以理解上面追加的意思應(yīng)該是與簡(jiǎn)單擴(kuò)展相反的,即展開(kāi)多次,包括對(duì)變量自身的展開(kāi)。~~?
遞歸展開(kāi)方式的定義格式為:VAR=var
簡(jiǎn)單擴(kuò)展方式的定義格式為:VAR:=var
make中的變量使用均使用的格式為:4上面的美元符號(hào)(VAR),~~這里csdn將美元符號(hào)自動(dòng)識(shí)別為指令不顯示~~?
注意:
1、變量名**是**不包括“:”、“#”、“=”以及結(jié)尾空格的任何**字符串**。同時(shí),變量名中應(yīng)只包含**字母、數(shù)字以及下劃線**,因?yàn)槠渌?hào)可能在將來(lái)被賦予特別的含義。
2、變量名大小寫(xiě)敏感。
3、推薦在makefile內(nèi)部使用**小寫(xiě)字母作為變量名**,預(yù)留**大寫(xiě)字母**作為控制隱含規(guī)則**參數(shù)**或用戶重載命令選項(xiàng)**參數(shù)**的變量名。