Makefile的介紹與使用(一)
Makefile是Linux系統中必不可缺的一部分,Makefile可以簡單理解為一份規則,也就是一個系統的執行指南,其規定了你所要執行的程式如何去做,需要什麼檔案參與等等。這部分就簡單瞭解一下子目錄下的Makefile。
一、最簡單的Makefile
最簡單的Makefile所需要的只有三個:target(目標檔案)、prerequisites(所依賴的檔案)、command(此目標檔案所需要執行的命令);
舉一個例子:
hello : hello.o
gcc hello.o -o hello
上例中,左上角的hello便是目標檔案(target),在其:後面的hello.o便是所依賴的.o檔案(prerequisites),而下一行的gcc hello.o -o hello便是此目標檔案所需執行的命令(command)。
gcc的格式並沒有固定,例如也是可行的,但是hello.o必須在hello的前面,即是錯誤的。(可以看成‘ -o hello ’必須以前移動)
接下來舉一個完整的例子:
hello : hello.o gcc -o hello hello.o hello.o : hello.c gcc -c hello.c clean : rm *.o hello
簡單說明一下上面程式碼的意思: 1、生成一個hello程式,此程式依賴於hello.o檔案,gcc...為其執行命令的方法。
2、hello.o檔案依賴於hello.c檔案。(一開始,hello.o檔案是不存在的,因為gcc -chello.c這個命令才會生成)
3、清除命令:清除(rm)所有的.o檔案(*.o)以及hello程式。
需要注意的是: 1、gcc...前面的一大片空白是Tab鍵,Makefile的編寫時非常嚴肅的,多一個空格都會出錯,這裡是Tab鍵就不要用空格隔開,否則就會出錯。
2、依賴關係是每一組檔案都會有的,而依賴關係的實質即說明了目標檔案是由哪些檔案生成的,亦或者是由哪些檔案更新的。
3、clean不是一個檔案而是一個動作,其冒號後什麼都沒有的時候,make就不會去找其依賴,也就不會執行其命令。
4、make會對target和prerequisite的修改日期進行比較,如果prerequisite檔案的日期比target檔案的日期要新,亦或者target檔案不存在,那麼make才會執行後續的命令。
接下來,我們執行一下此Makefile。
我們需要先編寫一個.c檔案,要求其在終端顯示“hello!!”
1 #include <stdio.h> 2 3 int main(void) 4 { 5 printf("hello!!\n"); 6 return 0; 7 }
此時我們這個資料夾內便有了hello.c和Makefile。
開啟終端進行make。
可以看出終端執行了兩條command命令,同時在此資料夾中生成了一個hello程式及hello.o檔案。
接下來我們跑一下所生成的hello程式。
可以看出hello程式其實就是hello.c的執行。
二、make的工作情況
上面演示時用了make執行,所以這裡簡單說明一下make的工作情況,看看make是如何工作的。
可以看出,我們在執行make時,出現了gcc -c hello.c以及gcc -o hello hello.o兩行程式碼,而這兩行是和我們所輸入command是一模一樣的。而我們所屬入的command是target找到prerequisite的路徑。由此也就可以看出make的工作情況為:通過command找到prerequisite,並以此生成target。如果在尋找依賴的過程中出現了問題(例如依賴找不到),那麼make就會退出並報錯。例如的執行就會找不到檔案,從而報錯。
而在make過程中,它會對prerequisite和target二者的日期進行比較,並以二者時間判斷是否進行重新連結。假如我們對.c檔案進行了更改,那麼.c檔案的時間就會在.o檔案之後,你再次make的時候它就會重新連結.c生成新的.o檔案,以此類推所生成的程式也就會更新。
通過“一”中的例子可以看出,clean並沒有被執行,因為其冒號後面是沒有東西的。而我們使用make也可以強制執行它,只要在終端輸入makeclean就可以強制執行clean命令,使得生成的hello.o檔案和hello程式全部清除。
三、在Makefile中使用變數
在我們編寫小程式的時候我們可以直接這樣將target、prerequisite以及command寫上去,沒什麼問題,也容易排查錯誤。但是在我們編寫一些比較大的程式的時候,我們這樣直接編寫,就會看起來很亂,並且容易敲錯,到時候再回來找錯就會非常困難。所以我們一般都會使用變數來將系統的一些定義,以後再次使用這個值的時候就會方便很多,而且也不易出錯。
Makefile中的變數有四種:自定義變數,自動變數,預定義變數,環境變數。
而我們一般情況下使用的都是自定義變數和自動變數,我也就對這兩種變數進行分析。
自定義變數:定義變數使用的變數名 := 變數值 使用變數 $(變數名)
仍然以hello為例:
HEL := hello.o hel := hello $(hel) : $(HEL) gcc -o $(hel) $(HEL) hello.o : hello.c gcc -c hello.c clean : rm *.o hello
可以看到這時我將HEL設為hello.o的變數名;將hel設為hello的變數名,然後將下面對應的hello和hello.o部分全部修改為$(變數名)的形態。 (可以看見,我有部分.o檔案改動,有部分維持原樣)
嘗試make,會發現此時和原來沒有改變的時候是一樣的。
自動變數:特殊巨集‘$@’,‘$^’,‘$<’等等
$@:規則的目標檔名 $^:規則的所有依賴檔案列表 $<:規則的第一個依賴檔名 (如果想知道更多的特殊巨集的作用可以自行百度)
所謂的自動變數便是系統已經定義好的一種使用規則,它並不會單獨特指某一變數,而是根據情況使用。
HEL := hello.o hel := hello $(hel) : $(HEL) gcc -o $@ $^ hello.o : hello.c gcc -c $^ clean : rm *.o hello
這樣寫的情況下,make的情況和上面是一樣的,是gcc -o hello.c和gcc -o hello hello.o