make的執行依賴於一個makefile文件,該文件告訴make應該如何執行編譯和鏈接操作。make通過比較對應文件的最后修改時間來決定哪些文件需要更新。make工具主要用來進行工程編譯和程序鏈接操作。當使用make時,工程中的如下幾種文件會被重新編譯:
- 所有從未被編譯過的源文件
- 執行make后,修改過的源文件
- 執行make后,修改過頭文件,則包含該頭文件的源文件都需要重新編譯
2.1 makefile簡介
Target : Prerequisites
command
...
...
Target: 目標
Prerequisites: 依賴
Command: 命令
一條規則可以有command,每個command占一行。command必須以Tab開頭。command用於在prerequisites改變后重建target。make程序根據規則的依賴關系來決定是否執行所定義的command,這個過程我們稱之為執行規則。
可以使用\來斷行,但是\后邊不能有空格。
makefile文件中沒有依賴項而只有command的目標稱為“偽目標”。
執行make時,將執行第一個定義的target。
注意:所有的command行都必須以Tab開始,但並不是所有以Tab開始的行都是command,make把出現在第一條規則之后的所有以Tab開始的行都作為command來處理。
頭文件和源文件如下:
1 // benxin.h 2 void print_benxin(); 3 4 // benxin.c 5 #include <stdio.h> 6 7 void print_benxin() 8 { 9 printf("benxin "); 10 } 11 12 // tuzi.h 13 void print_tuzi(); 14 15 // tuzi.c 16 #include <stdio.h> 17 18 void print_tuzi() 19 { 20 printf("tuzi !\n"); 21 }
1 // makefile 2 main : main.o \ 3 benxin.o tuzi.o 4 gcc -o main main.o benxin.o tuzi.o 5 main.o : main.c benxin.h tuzi.h 6 gcc -c main.c 7 benxin.o : benxin.c benxin.h 8 gcc -c benxin.c 9 tuzi.o : tuzi.c tuzi.h 10 gcc -c tuzi.c 11 clean : 12 rm main main.o benxin.o tuzi.o
執行:make
執行:./main
2.2 指定變量
可以指定一個變量表示所有的文件列表,如下:
OBJECTS = main.o benxin.o \
tuzi.o \
使用變量:
main : $(OBJECTS)
gcc –o main $(OBJECTS)
clean :
rm main $(OBJECTS)
2.3 Makefile組成
makefile文件中可能包含以下5個內容:顯式規則、隱式規則、變量定義、提示符、注釋。
- 顯式規則:規則中明確指定目標文件、依賴文件列表、更新目標所需的命令。
- 隱式規則:make程序根據目標文件名自動產生目標依賴文件列表,並使用默認的命令更新目標。
- 變量定義:定義一個變量表示一系列文件列表。
- 指示符:包含文件、條件執行、多行定義。
- 包含文件:include -----> 一個makefile文件中可以使用include包含另一個makefile文件中的內容,其告訴make程序,暫停執行當前makefile,而先去include指定的makefile,然后繼續執行。書寫include時獨立占據一行,但是不能以Tab鍵開始,格式如下:include FILENAMES...,其中,FILENAMES是shell所支持的文件名,可以使用通配符表示。如果被include的文件中存在變量或者函數,那么將會在包含它們的makefile中被展開。
-
- include的應用:
<1> 多個不同目錄下的makefile文件都使用一組同樣的變量或者模式規則,此時可以將這些共性的內容定義在一個文件中,然后在不同的makefile文件中include該文件。
<2> 當根據源文件自動產生依賴時,可以將這些依賴關系保存到一個特定的文件中,然后在makefile文件中include這個特定的文件,這樣可以減少錯誤。
- 注釋:用#表示注釋,因此如果需要在makefile的非注釋行中使用#時,需要加上轉義字符\,表示為”\#”。
2.4 makefile文件的指定規則
make程序默認會執行名為makefile或者Makefile的文件。否則需要通過-f或者—file選項來指定makefile文件,具體格式為:-f FILENAME或者—file=FILENAME。當然,也可以直接指定make的目標,只要當前文件夾下存在該目標的依賴文件列表即可。
2.5 MAKEFILES
如果當前環境中定義了MAKEFILES變量,那么make程序執行時,首先將此變量的值作為需要讀入的makefile文件。但是區別如下:
MAKEFILES變量指定的makefile文件中的“目標”不會被當作make執行的“終極目標”。
MAKEFILES變量指定的文件列表中的文件是否存在,make都不會提示錯誤。
make程序執行時,首先讀取MAKEFILES變量,然后才是當前工作目錄下的makefile文件。
2.6 MAKEFILE_LIST
make程序在讀取多個makefile文件時,比如,MAKEFILES變量、命令行、makefile、include等,在對這些文件進行解析之前,make讀取到的文件名會被自動加到MAKEFILE_LIST中。如此,我們可以通過判斷MAKEFILE_LIST變量的最后一塊內容來獲取當前make程序正在處理的makefile文件名。
2.7 特殊變量.VARIABLE
make包含一個特殊的變量,不能通過任何途徑給它賦值,其被展開后是makefile文件中當前點之前的所有全局變量列表,包括:空變量和make的內嵌變量。
2.8 makefile文件的重載
如果兩個makefile文件中擁有相同的目標,但是依賴與規則卻不同,此時使用include命令顯然行不通。此時需要使用“所有匹配模式 %”。%可以匹配任何一個目標,其依賴項假設為force,而force卻使用空命令。這是為了防止make程序試圖尋找一個規則去創建目標force時,又使用到% : force,這樣就陷入死循環了。
2.9 make解析makefile
<1>依次讀取變量MAKEFILES定義的makefile文件列表
<2> 讀取當前目錄中的makefile文件
<3> 讀取當前目錄makefile文件中使用的include包含的文件
<4> 查找重建所有已讀取的makefile文件的規則
<5> 初始化變量值並展開那些需要立即展開的變量和函數,同時根據預設條件確定執行分支
<6> 根據“終極目標”以及其他目標的依賴關系建立依賴關系鏈表
<7> 執行除“終極目標”以外的所有的目標規則
<8> 執行“終極目標”更新規則
附注知識點:
編譯: |
將高級語言程序轉換為機器碼的過程,結果為中間目標文件,linux中以后綴名.o標識目標文件。 |
鏈接:
|
將多個.o文件以及庫文件鏈接稱為可執行文件。鏈接器並不檢查函數所在的源文件,只檢查.o文件中定義的符號,將.o文件中使用的函數和庫文件中的函數進行合並,然后對合並后的符號重新排序,並鏈接上系統相關文件,最終生成可執行程序,Linux中的可執行程序為ELF格式。 |
靜態庫:
|
又名歸檔文件,其是多個.o文件的集合,庫中不同的.o文件之間沒有特殊的關系。Linux中靜態庫后綴名為.a,使用工具ar管理。 |
共享庫:
|
也是多個.o文件的集合,但是這些.o文件是由編譯器按照某種特殊方式生成的。Linux中,共享庫格式通常為ELF,即該類型庫具備可執行條件。 |