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