在學習Makefile時,首先是對其的語法不太瞭解,形成對項目的Makefile文件閱讀很吃力;其次是在尋找資源上,着實的浪費了很大的精力;最後就是對makefile的工做原理只知其一;不知其二,致使走了不少彎路。html
下面我將本身對Makefile的理解和認爲好的資料分享給你們,但願你們在接觸它時,能夠少走彎路。數組
一、在大型的項目中,源文件和目錄不計數,文件間的依賴關係及其所在路徑很是複雜;模塊化
二、文件間的編譯順序,哪些須要先編譯,哪些須要後編譯,哪些須要從新編譯,咱們不能經過簡單的編譯命令來完成; 函數
三、當咱們僅僅修改了部分文件的代碼,咱們不能經過只編譯更新過的文件來更快的完成編譯或者說是模塊化編譯。工具
這些問題,Makefile均可以解決, 一旦寫好,只須要一個make的命令,整個工程就會徹底自動編譯,極大的提升了軟件開發的效率。學習
能夠理解爲一種自動化編譯的工具,裏面包含了整個工程項目的編譯規則,而且能夠將項目分紅多個模塊進行分別編譯,並且裏面能夠包含執行操做系統的命令。當咱們須要編譯代碼時,只須要一個命令就可完成整個工程項目的編譯或者某個模塊的編譯。ui
你們都編譯過工程項目,對編譯過程應該瞭解,簡單說就是:源文件首先會生成中間目標文件,再由中間目標文件生成執行文件。 具體說就是:在編譯時,編譯器只檢測程序語法,和函數、變量是否被聲明。若是函數未被聲明,編譯器會給出一個警告,但能夠生成 Object File。而在連接程序時,連接器會在全部的 Object File 中找尋函數的實現,若是找不到,那到就會報連接錯誤碼(Linker Error)。若是向具體瞭解編譯過程,能夠參考http://my.oschina.net/u/1783725/blog/680722spa
Makefile格式操作系統
格式1: target ... : prerequisites ...
command (命令須要tab鍵)
...
....net
格式2:targets : prerequisites ; command
command (命令須要tab鍵)
...
target 也就是一個目標文件,能夠是 Object File,也能夠是執行文件。還能夠是一個標籤(Label)
prerequisites 就是要生成那個 target 所須要的文件或是目標。
command 也就是 make 須要執行的命令。 (任意的 Shell 命令)
工做原理: target 這一個或多個的目標文件,依賴於prerequisites 中的文件,其生成規則定義在 command 中
通俗的說:target 目標的生成,須要知足prerequisites 條件,條件知足才能執行command 來生成目標。
具體的說:若是prerequisites 中若是有一個以上的文件比 target 文件要新(更新日期要新)的話,command 所定義的命令就會被執行。這就是 Makefile 的規則。在編譯時,make會比較 targets 文件和 prerequisites 文件的修改日期, 若是 prerequisites 文件的日期要比 targets 文件的日期要新,或者 target 不存在的話,那麼,make 就會執行後續定義的命令。
例子
edit : main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o cc -o edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o main.o : main.c defs.h cc -c main.c kbd.o : kbd.c defs.h command.h cc -c kbd.c command.o : command.c defs.h command.h cc -c command.c display.o : display.c defs.h buffer.h cc -c display.c insert.o : insert.c defs.h buffer.h cc -c insert.c search.o : search.c defs.h buffer.h cc -c search.c files.o : files.c defs.h buffer.h command.h cc -c files.c utils.o : utils.c defs.h cc -c utils.c clean : rm edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o
一、make 會在當前目錄下找名字叫「Makefile」或「makefile」的文件。
二、若是找到,它會找文件中的第一個目標文件(target) ,在上面的例子中,他會找到「edit」這個文件,並把這個文件做爲最終的目標文件。
三、若是 edit 文件不存在,或是 edit 所依賴的後面的[.o]文件的文件修改時間要比edit 這個文件新,那麼,他就會執行後面所定義的命令來生成 edit 這個文件。
四、若是 edit 所依賴的.o 文件也存在,那麼 make 會在當前文件中找目標爲.o 文件的依賴性,若是找到則再根據那一個規則生成.o 文件。 (這有點像一個堆棧的過程)
五、固然,你的 C 文件和 H 文件是存在的啦,因而 make 會生成 .o 文件,而後再用 .o文件生命 make 的終極任務,也就是執行文件 edit 了。
注意:make 會一層又一層地去找文件的依賴關係,直到最終編譯出第一個目標文件,在找尋的過程當中, 若是出現錯誤, 好比最後被依賴的文件找不到, 那麼 make就會直接退出,並報錯,而對於所定義的命令的錯誤,或是編譯不成功,make 根本不理。make 只管文件的依賴性,即,若是在我找了依賴關係以後,冒號後面的文件仍是不在,那麼對不起,我就不工做啦。
經過上述分析,咱們知道,像 clean 這種,沒有被第一個目標文件直接或間接關聯,那麼它後面所定義的命令將不會被自動執行,不過,咱們能夠顯示要 make 執行。即命令——「make clean」 ,以此來清除全部的目標文件,以便重編譯。
第5點說的是一個make文件中makefile的執行流程,而第6點說的是整個項目中(多個make文件)makefile的執行流程。
一、讀入全部的 Makefile。
二、讀入被 include 的其它 Makefile。
三、初始化文件中的變量。
四、推導隱晦規則,並分析全部規則。
五、爲全部的目標文件建立依賴關係鏈。
六、根據依賴關係,決定哪些目標要從新生成。
七、執行生成命令。
經過上面的總結,你們對Makefile應該有一個大致的瞭解了吧,下面將會對其細節作一下總結。
一、顯示規則。顯示規則說明了,如何生成一個或多的的目標文件。這是由 Makefile 的書寫者明顯指出,要生成的文件,文件的依賴文件,生成的命令。
二、隱晦規則。因爲咱們的 make 有自動推導的功能,因此隱晦的規則可讓咱們比較粗糙地簡略地書寫 Makefile,這是由 make 所支持的。
三、變量的定義。在 Makefile 中咱們要定義一系列的變量,變量通常都是字符串,這個有點像 C 語言中的宏,當 Makefile 被執行時,其中的變量都會被擴展到相應的引用位置上。
四、文件指示。其包括了三個部分,一個是在一個 Makefile 中引用另外一個 Makefile,就像 C 語言中的 include 同樣;另外一個是指根據某些狀況指定 Makefile 中的有效部分,就像 C 語言中的預編譯#if 同樣;還有就是定義一個多行的命令。有關這一部分的內容,我會在後續的部分中講述。
五、註釋。Makefile 中只有行註釋,和 UNIX 的 Shell 腳本同樣,其註釋是用「#」字符,這個就像 C/C++中的「//」同樣。若是你要在你的 Makefile 中使用「#」字符,能夠用反斜框進行轉義,如: 「\#」
最後,還值得一提的是,在 Makefile 中的命令,必需要以[Tab]鍵開始。
僞目標:「僞目標」並非一個文件,只是一個標籤。 make 沒法生成它的依賴關係和決定它是否要執行,必須顯示地指明這個「目標」才能讓其生效
「僞目標」的取名不能和文件名重名,否則其就失去了「僞目標」的意義了,可使用一個特殊的標記「.PHONY」來顯示地指明一個目標是 「僞目標」
僞目標一樣能夠做爲「默認目標」 ,只要將其放在第一個,也能夠爲僞目標指定所依賴的文件。
使用「.PHONY」標記,放在文件首部的第一個目標,不會被make做爲執行目標。
make 支持通配符: 「*」 , 「?」和「[...]」,通配符能夠用在變量中,起做用必須用到wildcard 如objects := $(wildcard *.o)
注意:一、%.o: %.c 表示的是目標集爲當前目錄下全部.o結尾的文件,依賴集爲當前目錄下全部.c結尾的文件
如某目錄下有 test01.c test02.c test03.c文件,則%.o:%.c就表示3個,分別爲 test01.o:test01.c test02.o:test02.c test03.o:test03.c 。具體是否會生成.o文件,還須要看makefile文件中的依賴關係,需不須要生成.o文件。
二、.c.o 是老式風格的"後綴規則"——雙後綴,意義就是".c"是源文件的後綴,".o"是目標文件的後綴
後綴規則不容許任何的依賴文件,若是有依賴文件的話,那就不是後綴規則,那些後綴通通被認爲是文件名
.c.o: $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
(3)指定特定的makefile執行文件
Makefile make -f Make.Linux 或 make --file Make.AIX
(4)引用其它的makefile文件
格式 include <filename>
如: include foo.make a.mk b.mk c.mk e.mk f.mk
(5)一些經常使用變量
一、「$@」表示目標的集合,就像一個數組, 「$@」依次取出目標,並執於命令,如:
bigoutput littleoutput : text.g generate text.g -$(subst output,,$@) > $@ 等價於: bigoutput : text.g generate text.g -big > bigoutput littleoutput : text.g generate text.g -little > littleoutput
二、「$<」表示第一個依賴文件,依次取出目標,並執於命令
%.o:%.c $(CC) $(CFLAGS) -c -o $@ $<
依次取出.o的目標文件和.c的第一個依賴文件進行編譯。有多少個.o文件,就進行多少次編譯。
三、」$^「 表示全部的依賴文件
四、「@」字符在命令行前一般, make 會把其要執行的命令行在命令執行前輸出到屏幕上。當咱們用,那麼,這個命令將不被 make 顯示出來
(1)、《跟我一塊兒寫makefile》,一部很精闢的書,簡明扼要,全書無尿點
(2)、http://www.cnblogs.com/wang_yb/p/3990952.html (Makefile 使用總結 ),裏面的有關makefile的函數很全,能夠當作API來用
沙米的能力有限,但願你們留言,一塊兒交流。