Linux下Makefile的編寫與使用詳解
Makefile
一個工程文件中的源文件可能有很多,並且不同的功能、模塊等都放在不同的目錄中,常規的編譯已經不能高效化的處理這樣的問題,而Makefile就是為解決這一問題而來。
Makefile一旦寫好,隻需一個make指令,即可完成Makefile文件中所編寫的所有指令,從而編譯整個工程文件,極大的提高瞭效率。
make是一個命令工具,用來解釋Makefile中的命令。
Makefile文件命名和規則
文件命名
采用makefile或Makefile都可。
Makefile規則
Makefile中的命令規則如下:
xxx(目標文件):xxx(依賴文件)
(制表符)命令(shell命令)
其中,目標文件即最終要生成的文件(偽目標除外),依賴文件即生成目標文件所需的文件,命令即shell命令。
註意,命令前必須有一個tab縮進。
例如:
#Makefile app: a.c b.c #目標:依賴 gcc a.c b.c -o app #註意這行最開始的縮進
make以上這個Makefile後就會將目錄下的a.c與b.c編譯為目標文件app。
Makefile的工作原理
Makefile中的命令在執行前,會檢查是否存在所需的依賴文件
如果存在:執行命令
如果不存在:向下檢查其他規則,是否存在其他規則生成當前規則所需要的依賴,如果有,則執行該規則中的命令。
例如:
#Makefile app: a.o b.o gcc a.o b.o -o app a.o: a.c gcc -c a.c -o a.o b.o: b.c gcc -c b.c -o b.o
在上方這個Makefile中,當執行到app規則時,會發現所需的依賴文件a.o與b.o都不存在於當前目錄,所以會向下尋找是否有其他規則生成此文件,當尋找到a.o規則時,發現其是所需的文件,就執行gcc -c a.c -o a.o,b.o同理。
Makefile在執行規則中的命令時,會比較目標文件和依賴文件的修改時間
如果依賴文件晚於目標文件修改時間,即依賴文件在上一次生成目標後進行過修改,則會重新生成目標文件。
如果依賴文件早於目標文件修改時間,即依賴文件在上一次生成目標後沒進行修改,則不會執行相應的命令。
例如,你對一個Makefile使用兩次make,第二次會提示make:”app”已是最新。
利用這個特性,在加上我們將依賴與目標分級生成,即上方第二個Makefile,這樣當我們僅修改其中的a.c文件,再一次make隻會執行a.o規則與app規則,b.o規則因為b.c未修改而不執行,這樣可以大大減少資源浪費。
Makefile變量
以上雖然可以減少編譯代碼的重復量,但是如果一個工程中有1000個.c .h文件,我們編寫一個Makefile就會浪費大量時 間。因此,我們要采用一些變量來提高效率。
變量的獲取
我們使用 $(變量名) 來使用變量。
自定義變量
我們使用 變量名 = 變量值 如 var = hello來自定義我們所需的變量。
例如上方第一個Makefile就可改寫為:
#Makefile rsc = a.c b.c app: $(rsc) #目標:依賴 gcc $(rsc) -o app #註意這行最開始的縮進
預定義的變量
有部分變量是系統預定義的,我們可以直接使用。
AR:歸檔維護程序的名稱,默認值為ar
CC:C編譯器的名稱,默認值為cc
CXX:C++編譯器的名稱,默認值為g++
$@:目標的完整名稱
$<:第一個依賴文件的名稱
$^:所有依賴文件的名稱
為瞭方便理解接下來的例子,我們簡單講解一下Makefile中的模式匹配。
%.o:%.c 中,%是 通配符,匹配一個字符串,而兩個%則匹配同一個字符串。
例如上方第二個Makefile可改寫為:
#Makefile rcs = a.o b.o app: $(rcs) $(CC) $(rcs) -o $@ %.o: %.c #上方規則會執行兩次此規則 $(CC) -c $< -o $@
Makefile函數
我們可以看到,上面這個Makefile已經相對簡單瞭,但是,還是沒有解決工程中文件很多的情況,rcs的獲取還是要我們輸入每個需要編譯的文件,那麼,就要采用函數來替我們去寫入這些依賴文件。
$(wildcard PATTERN. . .)
這個函數的功能是獲取指定目錄下指定類型的文件。
其中參數PATTERN是某個目錄下某種類型的文件,多個目錄多個類型可用空格分隔。
返回值是一個若幹個文件的文件列表,文件名用空格隔開。
例如:
$(wildcard ./*.c) 返回當前目錄下的所有以c為後綴的文件。
$(patsubst pattern, replacement, text)
這個函數的功能是查找text中的單詞是否符合模式pattern,如果符合,則用replacement替換。
pattern可以包括通配符 % 。如果replacement中也包含 % ,那麼replacement中的 % 將和 pattern中的 % 保持一致。
返回值為替換後的字符串。
例如:
$(patsubst %.c, %.o, a.c, b.c) 返回a.o, b.o。
這樣,我們上面那個例子就可以改寫為:
#Makefile rcs = $(wildcard ./*.c) objs = (patsubst %.c, %.o, $(src)) app: $(objs) $(CC) $(objs) -o $@ %.o: %.c #上方規則會執行兩次此規則 $(CC) -c $< -o $@
Makefile clean規則
在我們執行完make指令後,會發現當前目錄下多出瞭很多以o為後綴的文件,但是我們僅需要最終的目標文件app,其他的都是多餘的,我們該如何處理。clean規則就會幫助我們處理他們。
clean
我們隻用將clean規則添加到Makefile的最後,即可在每次編譯完成後執行clean規則中的命令。如:
#Makefile rcs = $(wildcard ./*.c) objs = (patsubst %.c, %.o, $(src)) app: $(objs) $(CC) $(objs) -o $@ %.o: %.c #上方規則會執行兩次此規則 $(CC) -c $< -o $@ clean: rm $(objs) -f #rm指令刪除 -f迭代刪除
但是你會發現當前目錄下多出瞭一個clean目標文件,依舊會采用Makefile的策略,對比修改時間,導致我們時常及時執行瞭clean,還是無法清除文件,那麼,我們就需要接下來這個操作。
我們將clean定義為偽目標,即 .PHONY:clean 那麼它就不會生成目標文件,少瞭對比,那麼每次都會執行。
例如:
#Makefile rcs = $(wildcard ./*.c) objs = (patsubst %.c, %.o, $(src)) app: $(objs) $(CC) $(objs) -o $@ %.o: %.c #上方規則會執行兩次此規則 $(CC) -c $< -o $@ .PHONY: clean #偽目標 clean: rm $(objs) -f #rm指令刪除 -f迭代刪除
到此這篇關於Linux下Makefile的編寫與使用詳解的文章就介紹到這瞭,更多相關Linux Makefile編寫與使用內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- shell腳本編程Makefile的使用
- Makefile構建Golang項目示例詳解
- golang構建工具Makefile使用詳解
- Ubuntu編譯內核模塊,內容體現系統日志中
- nginx rtmp模塊編譯 arm版本的問題