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