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