在Makefile中,最重要的三個(gè)概念是:目標(biāo)(target)、依賴(lài)關(guān)系(dependency)和命令(command)。目標(biāo)是指要干什么,即運(yùn)行make后生成什么;依賴(lài)是指明目標(biāo)所依賴(lài)的其他目標(biāo);命令則告訴make如何生成目標(biāo),這三個(gè)概念是通過(guò)Makefile中的規(guī)則(rule)關(guān)聯(lián)在一起的。
例 1 編輯一個(gè)名為 Makefile 的文件,文件內(nèi)容如下:
all:
echo “Hello Lion, I love you”
然后在命令行中執(zhí)行它,鍵入集合 make ,就能執(zhí)行。編輯 makefile 文件時(shí)要注意,命令所在的行必須以 Tab 鍵開(kāi)頭。
在Makefile中,目標(biāo)和命令組合在一起就形成了一個(gè)簡(jiǎn)單的規(guī)則,通過(guò)這個(gè)規(guī)則,我們告訴 make 要做什么。運(yùn)行 make 命令時(shí)可以指定具體的目標(biāo)加以選擇。
例 2 繼續(xù)編輯修改剛才的 Makefile 文件,如下:
all:
echo “Hello Lion, I love you”
test:
echo “Just for test, she is so beautiful”
綜上,我們得到以下信息:一個(gè)Makefile中可以定義多個(gè)目標(biāo);調(diào)用 make 命令時(shí),得告訴它我們希望構(gòu)建的目標(biāo)是什么,即要它執(zhí)行哪個(gè)命令,第一個(gè)目標(biāo)是默認(rèn)執(zhí)行的目標(biāo);當(dāng) make 得到目標(biāo)后,先找到構(gòu)建目標(biāo)的對(duì)應(yīng)規(guī)則,然后運(yùn)行規(guī)則中的命令來(lái)達(dá)到構(gòu)建目標(biāo)的目的,一個(gè)規(guī)則中可以根據(jù)需要存在多條命令。
如果不想讓 make 打印出每條要執(zhí)行的命令,可以在命令前加上 @ 符號(hào),如
all:
@ echo “Hello Lion, I love you”
test:
@echo “Just for test, she is so beautiful”
先決條件:在執(zhí)行一個(gè)目標(biāo)前,必須要先執(zhí)行其他目標(biāo),即當(dāng)前目標(biāo)的執(zhí)行是以其他目標(biāo)的執(zhí)行為條件。這個(gè)先決目標(biāo)就是當(dāng)前要執(zhí)行的目標(biāo)要依賴(lài)的目標(biāo)。如把剛才的 Makefile 修改如下:
all: test
@echo “Hello Lion, I love you”
test:
@echo “Just for test, she is so beautiful”
然后再次執(zhí)行命令 make ,運(yùn)動(dòng)結(jié)果如下:
$ make
Just for test, she is so beautiful!
Hello Lion, I love you!
從結(jié)果可以看到,test 目標(biāo)先被構(gòu)建了,然后才構(gòu)建 all 目標(biāo),因?yàn)?test 目標(biāo)是 all 目標(biāo)的先決條件。出現(xiàn)這種目標(biāo)依賴(lài)關(guān)系時(shí), make 會(huì)從左到右(在同一規(guī)則中)和從上到下(在不同的規(guī)則中)的先后順序先構(gòu)建一個(gè)規(guī)則所依賴(lài)的每一個(gè)目標(biāo),形成一種“鏈?zhǔn)椒磻?yīng)”。
在我看來(lái),學(xué)會(huì)寫(xiě)簡(jiǎn)單的Makefile,閱讀較復(fù)雜的makefile,是每一個(gè)Linux程序員都必須擁有的基本素質(zhì)。Makefile可以自動(dòng)識(shí)別哪些源文件被更改過(guò),需要重新編譯,那些不需要。從而節(jié)省大型工程重新編譯的時(shí)間。規(guī)則如下:
如果這個(gè)工程沒(méi)有編譯過(guò),那么我們的所有C文件都要編譯并被鏈接。
如果這個(gè)工程的某幾個(gè)C文件被修改,那么我們只編譯被修改的C文件,并鏈接目標(biāo)程。
如果這個(gè)工程的頭文件被改變了,那么我們需要編譯引用了這幾個(gè)頭文件的C文件,并鏈接目標(biāo)程序。
學(xué)會(huì)編寫(xiě)Makefile,不僅僅有益于你在Linux下編寫(xiě)大型工程。同時(shí)也能幫助你理解編譯原理。遠(yuǎn)離IDE,了解編譯過(guò)程。
Makefile: 程序模塊的內(nèi)部關(guān)系決定了源程序編譯和鏈接的順序,通過(guò)建立makefile可以描述模塊間的相互依賴(lài)關(guān)系。Make命令從中讀取這些信息,然后根據(jù)這些 信息對(duì)程序進(jìn)行管理和維護(hù)。在makefile里主要提供的是有關(guān)目標(biāo)文件(即target)與依靠文件(即dependencyies)之間的關(guān)系,還 指明了用什么命令生成和更新目標(biāo)文件。有了這些信息,make會(huì)處理磁盤(pán)上的文件,如果目的文件的時(shí)間標(biāo)志(該文件生成或被改動(dòng)進(jìn)的時(shí)間)比任意一個(gè)依靠 文件舊,make就執(zhí)行相應(yīng)的命令,以便更新目的文件(目的文件不一定是最后的可執(zhí)行文件,它可以是任何一個(gè)文件)。
1)makefile的基本單位是“規(guī)則”,即描述一個(gè)目標(biāo)所依賴(lài)的文件或模塊,并給出其生成和算法語(yǔ)言需要用到的命令。規(guī)則的格式如下:
目標(biāo)[屬性]
分隔符號(hào) [依賴(lài)文件][命令列]
{《tab》命令列}
與Linux下面的命令格式相同,[]中的內(nèi)容表示為可選擇項(xiàng),{}中的內(nèi)容表示可出現(xiàn)多次。
A. 目標(biāo):目標(biāo)文件列表,即要維護(hù)的文件列表。
B. 屬性:表示該文件的屬性。
C. 分隔符:用來(lái)分割目標(biāo)文件和依賴(lài)文件的符號(hào),如冒號(hào)“:”等。
D. 依賴(lài)文件:目標(biāo)文件所依賴(lài)的文件的列表。
E. 命令列:重新生成目標(biāo)文件的命令,可以有多條命令。
注 意:在makefile中,除了第一條命令,每一個(gè)命令行的開(kāi)頭必須是一個(gè)《tab》符號(hào),也就是制表符,而不能因?yàn)橹票矸喈?dāng)于4個(gè)空格而 不去鍵入tab符號(hào)。因?yàn)閙ake命令是通過(guò)每一行的tab符號(hào)來(lái)識(shí)別命令行的。另外,對(duì)于第一條命令而言,不必用《tab》鍵,就可以直接 跟在依賴(lài)文件的列表后面。對(duì)于注釋的了,起頭應(yīng)該用#符號(hào),并用換行符號(hào)結(jié)束。如果要引用#符號(hào),要用到“”。
2) make命令的使用格式為:
make [選項(xiàng)][宏定義][目標(biāo)文件]
make命令有多個(gè)選項(xiàng)參數(shù),列舉參數(shù)含義如下:
A. -f:指定需要維護(hù)的目標(biāo)。
B. -i:忽略運(yùn)行makefile中命令產(chǎn)生的錯(cuò)誤,不退出make.
C. -r:忽略?xún)?nèi)部規(guī)則。
D. -s:執(zhí)行但是不顯示所執(zhí)行的命令。
E. -x:將所有的宏定義都輸出到shell環(huán)境。
F. -V:列出make的版本號(hào)。
選項(xiàng)給出了make命令工作的方式方法,宏定義給出了makefile時(shí)所用的宏值,目標(biāo)文件就是需要更新的文件列表。
3)使用偽目標(biāo):make命令的目標(biāo)可分為實(shí)目標(biāo)和偽目標(biāo)兩種。而有時(shí)需要用make命令來(lái)做些輔助性的工作,或者對(duì)多個(gè)文件進(jìn)行維護(hù)??梢酝ㄟ^(guò)設(shè)置偽目標(biāo)來(lái)實(shí)現(xiàn)。
4)指定需要維護(hù)的目標(biāo):一般make維護(hù)的是makefile中的第一個(gè)目標(biāo)文件。但有時(shí)用戶(hù)并不關(guān)心最終的目標(biāo)文件如何。反而關(guān)心中間的目標(biāo)文件。使用目標(biāo)參數(shù)make的執(zhí)行。
5)makefile 變量:makefile里主要包含了一些規(guī)則,除此之外就是變量定義,被稱(chēng)為宏定義。Makefile里的變量就像一個(gè)環(huán)境變量。事實(shí)上,環(huán)境變量在 make過(guò)程中可以看成make的變量。這些宏定義是大小寫(xiě)敏感的,一般使用大寫(xiě)字母。它們幾乎可以從任何地方被引用,也可以被用來(lái)做很多事情,比如:
A.儲(chǔ)存一個(gè)文件名列表:生成可執(zhí)行文件的規(guī)則包含一些目標(biāo)文件名作為依賴(lài)文件。在這個(gè)規(guī)則的命令行里,同樣的那些文件被輸送給gcc做為命令參數(shù)。如果在這里使用一個(gè)宏來(lái)儲(chǔ)存所有目標(biāo)文件名,那么就會(huì)很容易加入新的目標(biāo)文件,而且不易出錯(cuò)。
B.儲(chǔ)存可執(zhí)行文件名:如果程序被用在一個(gè)非GCC的系統(tǒng)里,或者想使用一個(gè)不同的編譯器,就必須將所有使用編譯器的地方改成新的編譯器名。但是如果使用一個(gè)宏來(lái)代替編譯器名,那么只需要改變一個(gè)地方,其他所有地方的命令名就都改變了。
C.儲(chǔ) 存編譯器命令選項(xiàng):假設(shè)想給所有的編譯命令傳遞一組相同的選項(xiàng)(例如-Wall -O -g),如果把這組選項(xiàng)存入一個(gè)宏,那么可以把這個(gè)宏放在所有調(diào)用編譯器的地方。而當(dāng)要改變選項(xiàng)的時(shí)候,只需在宏定義的地方改變這個(gè)變量的內(nèi)容。要定義一 個(gè)宏,只要在一行的開(kāi)始寫(xiě)下這個(gè)宏的名字,后面跟一個(gè)“=“和要設(shè)定這個(gè)變量的值。以后引用這個(gè)變量時(shí),寫(xiě)一個(gè)$符,后面是括號(hào)里的變量名。格式如下:
$(宏名) 或${宏名}
make將$符號(hào)作為引用的開(kāi)始。如果要表示$符號(hào),那么應(yīng)用$$即可。宏引用還支持多層引用,在處理時(shí)按照順序依次展開(kāi)。當(dāng)宏名是單個(gè)字符時(shí),可以省略括號(hào),宏定義可以在makefile文件中。
I.$@:擴(kuò)展成當(dāng)前規(guī)則的目標(biāo)文件名
II.$《:擴(kuò)展成依賴(lài)列表中的第一個(gè)依賴(lài)文件
III.$^:擴(kuò)展成整個(gè)依賴(lài)的文件列表(除掉了里面所有重復(fù)的文件名)
IV.$?:表示目標(biāo)文件中新的依賴(lài)文件的列表
V.$*:是表示依賴(lài)文件的文件名,不含擴(kuò)展名
6)在makefile中使用函數(shù):makefile里的函數(shù)跟它的變量很相似。在調(diào)用時(shí),用一個(gè)$開(kāi)始,是開(kāi)括號(hào),函數(shù)名,再空格,然后跟一列由逗號(hào)分隔的參數(shù),最后用關(guān)括號(hào)結(jié)束。
以上,是對(duì)Makefile的一個(gè)簡(jiǎn)單入門(mén)介紹,一般,用以閱讀大多數(shù)的Makefile都已經(jīng)足夠了。
評(píng)論
查看更多