makefile增量編譯(生成依賴關係)

1      Makefile基本用法

1.1      常用符號

1.1.1        編譯器

CC   // C語言編譯器,默認值爲gcc 默認的變量,無需用戶自定義,也可以改變其值

CXX  // C++語言編譯器,默認值爲g++ 默認的變量,無需用戶自定義,也可以改變其值

CFLAGS   // C語言編譯器的編譯選項

LDFLAGS  // C語言編譯器的鏈接選項

CXXFLAGS // C++語言編譯器的編譯選項

1.1.2        自動化變量

$@ 代表規則中的目標文件名。如果目標是一個文檔(Linux中,一般稱.a文件爲文檔),那麼它代表這個文檔的文件名。在多目標的模式規則中,它代表的是哪個觸發規則被執行的目標文件名。

$% 規則的目標文件是一個靜態庫文件時,代表靜態庫的一個成員名。例如,規則的目標是“foo.a(bar.o)”,那麼,“$%”的值就爲“bar.o”,“$@”的值爲“foo.a”。如果目標不是函數庫文件,其值爲空。

$< 規則的第一個依賴文件名。如果是隱含規則,則它代表通過目標指定的第一個依賴文件。

$? 所有比目標文件更新的依賴文件列表,空格分割。如果目標是靜態庫文件名,代表的是庫成員(.o文件)的更新情況。

$^ 規則的所有依賴文件列表,使用空格分隔。如果目標是靜態庫文件名,它所代表的只能是所有庫成員(.o文件)名。一個文件可重複的出現在目標的依賴中,變量“$^”只記錄它的一次引用情況。就是說變量“$^”會去掉重複的依賴文件。

$+ 類似“$^”,但是它保留了依賴文件中重複出現的文件。主要用在程序鏈接時,庫的交叉引用場合。

$(@D) 代表目標文件的目錄部分(去掉目錄部分的最後一個斜槓)。如果“$@”是“dir/foo.o”,那麼“$(@D)”的值爲“dir”。如果“$@”不存在斜槓,其值就是“.”(當前目錄)。注意它和函數“dir”的區別!

$(@F) 目標文件的完整文件名中除目錄以外的部分(實際文件名)。如果“$@”爲“dir/foo.o”,那麼“$(@F)”只就是“foo.o”。“$(@F)”等價於函數“$(notdir $@)”。

$(%D),$(%F) 當以如“archive(member)”形式靜態庫爲目標時,分別表示庫文件成員“member”名中的目錄部分和文件名部分。它僅對這種形式的規則目標有效。

$(<D),$(<F) 分別表示規則中第一個依賴文件的目錄部分和文件名部分。

$(^D),$(^F) 分別表示所有依賴文件的目錄部分和文件部分(不存在同一文件)。

$(+D),$(+F) 分別表示所有依賴文件的目錄部分和文件部分(可存在重複文件)。

$(?D),$(?F) 分別表示被更新的依賴文件的目錄部分和文件部分。

是通配符,%.c表示工程裏的.c文件

命令行以'@'打頭的含義: 在執行到的時候不回顯相應的命令內容,只顯示命令的輸出。

“-” 命令行以'-'打頭的含義: 在執行到的時候如果發生錯誤(退出返回非零狀態)時,不中斷make過程。

“+” 命令行以'+'打頭的含義: makefile中以+開頭的命令的執行不受到 make的-n,-t,-q三個參數的影響。我們知道,在make的時候,如果加上-n, -t, -q這樣的參數,都是不執行相應命令的,而以'+'開頭的命令,則無論make命令後面是否跟着三個參數,都會被執行。

1.2      變量

1.2.1        變量定義

OBJ = ../objs

make變量(Makefile中定義的或者是make的環境變量)的引用使用“$(VAR)”格式。

1.2.2        變量賦值

= 當它的右邊賦值是變量時,這個變量的定義在本條語句之前或之後都可以,即可以遞歸展開。

:= 它右邊賦得值如果是變量,只能使用在這條語句之前定義好的,而不能使用本條語句之後定義的變量,即不可以遞歸展開。

?= 該符號左邊的變量,如果在本條語句之前沒有定義過,則執行本語句,如果已經定義,那麼本語句什麼都不做。

+= 是添加等號後面的值

1.2.3        變量操作

$(VAR:A=B)  同${VAR:A=B}

${VAR:A=B} 替換變量“VAR”中所有“A”字符結尾的字爲“B”結尾的字。“結尾”的含義是空格之前(變量值的多個字以空格分開)

1、wildcard : 擴展通配符 src=$(wildcard *.c ./sub/*.c) 取當前路徑和sub路徑下的所有.c

                                   src = a.c b.c ./sub/c.c ./sub/d.c 

2、notdir : 去除路徑    file=$(notdir $(src))

                                          file = a.c b.c c.c d.c

3、dir:獲取路徑         dir=$(dir $(src))

                                   dir = .  .  ./sub  ./sub

4、patsubst :替換通配符  obj=$(patsubst %.c,%.o,$(file) ) 可用於構造目標文件

                                    obj = a.o b.o c.o d.o

5、sed:替換指定字符串 sed 's/要替換的字符串/新的字符串/g'   (要替換的字符串可以用正則表達式),可以用 –i 直接替換文件內容

6、grep:(global search regular expression(RE) and print out the line,全面搜索正則表達式並把行打印出來)是一種文本搜索,使用正則表達式搜索文本,並把匹配的行打印出來。

grep "\$(COMPONENT_NAME)_SRC =" $MK_PATH/$1.mk >> makefiles/$1_files.mk

1.3      Makefile的編寫

Makefile的作用就是實現自動化編譯,它關係到了整個工程的編譯規則。一個工程中可能包含很多的源文件,並且按功能,模塊等分別存放在特定的目錄中,makefile定義了一系列的跪着來指定哪些文件需要先編譯,哪些文件需要後編譯,哪些要重新編譯,以及更復雜的操作。Makefile寫好之後,只需要一個make命令,整個工程就可以自動編譯,極大地提高了軟件開發的效率。

1.3.1        依賴關係

Makefile其實就是爲了指定文件依賴性的問題,下面的例子中,target也就是一個目標文件,可以是Object File,也可以是執行文件。還可以是一個標籤(Label),作爲一個僞目標存在。下面的command就是make要執行命令,可以是編譯或者鏈接命令或者是任意的shell命令,但是命令前必須用tab縮進。Make會把include指令所指定的任何文件視爲一個需要更新的工作目標(GNU+Make項目管理第三版P43)

target ... : prerequisites ...

command

...

1.3.2        工作方式

當我們輸入make 命令時:

1、make會在當前目錄下找名字叫“Makefile”或“makefile”的文件。

2、如果找到,它會找文件中的第一個目標文件(target),在上面的例子中,他會找到“edit”這個文件,並把這個文件作爲最終的目標文件。

3、如果edit文件不存在,或是edit所依賴的後面的 .o 文件的文件修改時間要比edit這個文件新,那麼,他就會執行後面所定義的命令來生成edit這個文件。

4、如果edit所依賴的.o文件也存在,那麼make會在當前文件中找目標爲.o文件的依賴性,如果找到則再根據那一個規則生成.o文件。(這有點像一個堆棧的過程)

5、當然,你的C文件和H文件是存在的啦,於是make會生成 .o 文件,然後再用 .o 文件生命make的終極任務,也就是執行文件edit了。

通常makefile的最後會有一個clean目標,沒有被第一個目標文件直接或間接關聯,那麼它後面所定義的命令將不會被自動執行,不過,我們可以顯式要make執行。即命令——“make clean”,以此來清除所有的目標文件,以便重編譯。

1.3.3        自動生成依賴關係

在19B的編譯過程中,每次編譯都需要執行clean命令清除所有的所有的目標文件,否則,新的代碼修改就不會生效,極大地降低了編譯效率,通常這種情況的原因是makefile的依賴關係不全或者依賴關係有誤。

對19B的編譯過程進行梳理髮現其依賴關係中僅對.c文件進行了依賴,沒有將頭文件包含進去,這樣當頭文件更改時,不會觸發任何編譯。所以出現了必須clean重編譯的效率問題。

完善所有目標文件的依賴關係工作量是巨大的,好在gcc爲我們提供了自動生成依賴關係的選項。

定義make-depend程序自動生成依賴規則:

b1c6625872d69cc48103_481x104.png@900-0-90-f.pnguploading.4e448015.gif轉存失敗重新上傳取消b1c6625872d69cc48103_481x104.png@900-0-90-f.pnguploading.4e448015.gif轉存失敗重新上傳取消b1c6625872d69cc48103_481x104.png@900-0-90-f.pnguploading.4e448015.gif轉存失敗重新上傳取消

-MM選項可以爲我們生成依賴關係,並且相比-M它省略了標準的頭文件,使得依賴關係儘量不那麼混亂。

-MF選項用來指定依賴關係文件,通常把目標文件的後綴.o替換成.d。當然也可以使用-MD或者-MMD自動生成類似的文件名,但是它無法加入目標文件的相對路徑,只能將.d放在當前目錄。

-MP選項用來指示gcc爲每一個依賴文件加入假想工作目標,這樣當代碼重構造成某個被依賴的頭文件刪除時,不會出現no rule to make target deleted.h的錯誤,而是認爲其尚未被更新,所有依賴其的目標都會被重新編譯,對應的依賴文件也會重新生成,進而使deleted.h自然的從makefile中消失。

-MT選項後的字符串做爲依賴文件中的工作目標,從而使目標文件可以帶上路徑信息。

上面只是一個宏定義的函數,我們在基本依賴關係中必須調用這個函數來使其得以執行,並在最後通過include選項將其包含進來(“-”是爲了在.d不存在時不發生錯誤)。

299ac25872d69d36fb62_553x58.jpg@900-0-90-f.jpguploading.4e448015.gif轉存失敗重新上傳取消299ac25872d69d36fb62_553x58.jpg@900-0-90-f.jpguploading.4e448015.gif轉存失敗重新上傳取消299ac25872d69d36fb62_553x58.jpg@900-0-90-f.jpguploading.4e448015.gif轉存失敗重新上傳取消

5c01c25872d69d8a90b4_211x54.jpg@900-0-90-f.jpguploading.4e448015.gif轉存失敗重新上傳取消5c01c25872d69d8a90b4_211x54.jpg@900-0-90-f.jpguploading.4e448015.gif轉存失敗重新上傳取消5c01c25872d69d8a90b4_211x54.jpg@900-0-90-f.jpguploading.4e448015.gif轉存失敗重新上傳取消

這樣,每個.o依賴於.c並由include來的依賴關係對其依賴規則進行補充,在第一次編譯不存在依賴文件時每個.o也不存在,編譯就可以生成依賴文件,在後續增量編譯過程中,源文件的改變可能會導致依賴關係的改變,並會觸發.o重新編譯,在.o更新時會調用make-depend重新更新.d,進而完成增量編譯過程中,只更新需要更新的文件,並且更新了所有需要更新的文件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章