首先介紹make實用程序的語法和常用選項,然后細剖makefile文件的組成。make命令
注意:在源文件沒有被修改的情況下,運行make命令會生成一條消息,說源文件的可執行文件是最新的,不需要用make命令重新編譯和鏈接。要強制再創建可執行代碼,需要改變源文件的上次更新時間,可以使用touch命令,然后再次運行make命令。
makefile規則make程序基于文件之間的依賴性,需要建立的目標文件,以及建立目標文件時要執行的命令,以上所有被稱為規則,存放在文件makefile中。定制規則的語法如下:目標列表 : 關聯性列表<TAB>命令列表注意:1.可以在關聯性列表和命令列表中使用shell文件名模式匹配字符,例如?、*、[]等等。2.如果目標的命令列表中某個命令前面帶有@,那么當make程序執行時,該命令是不會有反應的,在程序運行完畢之后,所有前面帶@的命令按照反序執行。可以通過執行make -n命令顯示這些命令以供查看。3.如果目標的命令列表中某個命令前面帶有-,說明如果該命令執行有誤,會跳過該命令并繼續執行。make程序使用makefile中的規則決定程序中需要重新編譯的文件,并再次鏈接生成可執行代碼。如果源文件上修改的時間戳比目標文件上的時間戳更新,那么make重新編譯build中包含的源文件。例如,如果修改了一個.h頭文件,make程序就會重新編譯所有包含該頭文件的源文件,前提是頭文件在這些源文件的目標文件的關聯性列表中;再如某.c源文件被修改,那么該源文件被重新編譯,生成對應的新的目標文件。myprog : foo.o bar.o gcc –o myprog foo.o bar.ofoo.o : foo.c foo.h bar.h gcc –o foo.o –c foo.cbar.o : bar.c bar.h gcc –o bar.o –c bar.c上述規則中,只要目標文件比冒號后面的文件任何一個舊,將會執行下一行的命令;但是在檢查foo.o和bar.o的時間之前,會往下查找那些把foo.o和bar.o作為目標文件的規則;以此類推,并最終回到myprog規則。如何得到每個C文件的輸出規則呢?可使用-M和-MM編譯選項。注意:使用-M和-MM編譯選項時,僅在shell中輸出規則信息,不能用于產生可執行文件,即不能寫成gcc -o hello -M hello.c這樣的形式。gcc –M hello.c //輸出hello.c和該文件中所有<>和””包含的頭文件gcc –MM hello.c //僅輸出hello.c和該文件中所有””包含的頭文件后綴(隱含)規則make -p命令顯示了所有后綴規則列表。為了建立一個目標,make使用程序會遍歷一連串的依賴關系,從而決定從何處開始建立。如果沒有找到目標文件,make程序按照優先順序查找源文件,首先查找.c、.f或.s后綴的文件,然后再查找SCCS(帶.c~后綴)文件,如果沒有找到任何一個源文件,make程序就會報告一個異常。make程序知道調用gcc -c xxx.c -o xxx.o的預定義命令,而且還知道目標文件通常和源文件是相同的,這種功能稱作標準依賴性,所以foo.o : foo.c foo.h bar.h這樣的語句可以簡寫成foo.o : foo.h bar.h。同時,如果把生成foo.o和bar.o的命令從規則中刪除,make將自動查找它的隱含規則(gcc -M/MM輸出的代碼),然后找到一個適當的命令,命令中會使用一些變量,并且按照一定步驟設定。因此,上述makefile的內容可以根據后綴規則簡寫成:myprog : foo.o bar.o gcc –o myprog foo.o bar.ofoo.o : foo.h bar.hbar.o : bar.h宏定義(變量)makefile中的變量定義可以存儲文件名列表、可執行文件名以及編譯器標識等,主要是使用如下方法:
未使用后綴規則的makefile文件變成如下:OBJS=foo.o bar.oSOURCES=foo.c bar.cHEADERS=foo.h bar.hCC=gccCFLAGS=-Wall -O -gmyprog : $(OBJS) $(CC) $^ -o $@foo.o : foo.c foo.h bar.h $(CC) $(CFLAGS) –c $< -o $@bar.o : bar.c bar.h $(CC) $(CFLAGS) –c $< -o $@而使用了后綴規則的makefile文件變成如下:OBJS=foo.o bar.oSOURCES=foo.c bar.cHEADERS=foo.h bar.hCC=gccmyprog : $(OBJS) $(CC) S^ -o $@foo.o : foo.h bar.hbar.o : bar.h虛目標假設一個項目最后需要產生兩個可執行文件exec1和exec2,但兩個文件是相互獨立的,此時可使用假想目的all來達到效果。all : exec1 exec2all文件并不存在,make總是會假設它需要被生成,因此會檢查它的依靠文件exec1和exec2是否需要更新,當把它的依靠文件更新后,就會執行它的規則里的命令行,但是在規則里沒有哪個命令作用于名為all的實際文件,所以該規則并不真正改變all的狀態。注意下面的語句用法,這些語句可以添加到makefile文件后:myprog.tar : makefile $(SOURCES) $(HEADERS) tar -cvf $@ S^clean : rm *.o當make命令不帶參數執行時,最后兩個目標myprog.tar和clean的命令不會執行,因為這些文件沒有依賴文件。將這兩個目標作為參數傳遞給make命令,可以調用與目標關聯的命令。例如:執行make myprog.tar命令會執行tar -cvf myprog.tar makefile foo.c bar.c foo.h bar.h語句,而執行make clean命令會執行clean *.o語句。下面給出一個較完整的makefile文件:---------------------------------------------------------#Updated makefile that uses some built-in macros and#@-preceded commandsdefine CC gccendefOPTIONS=-03OBJECTS=main.o input.o compute.oSOURCES=main.c input.c compute.cHEADERS=main.h input.h compute.hcomplete : power @echo "Build complete"power : $(OBJECTS) $(CC) $(OPTIONS) -o $@ $^ -lm @echo "The executable is in the 'power' file"main.o : main.h input.h compute.hcompute.o : compute.hinput.o : input.hpower.tar : makefile $(HEADERS) $(SOURCES) tar -cvf $@ $^clean : rm -f *.o-----------------------------------------------------執行結果為:-----------------------------------------------------$ makegcc -c main.c -o main.ogcc -c input.c -o input.ogcc -c compute.c -o compute.ogcc -o3 -o power main.o input.o compute.o -lmThe executable is in the 'power' fileBuild complete$ make power.tartar -cvf power.tar makefile main.h input.h compute.h main.c input.c compute.cmakefilemain.hinput.hcompute.hmain.cinput.ccompute.c$ make cleanrm -f *.o------------------------------------------------------