Makefile的基本編寫與優化

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"},{"type":"color","attrs":{"color":"#808080","name":"user"}}],"text":"提示:本文中使用的操作系統環境爲Ubuntu18.0/64位。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"},{"type":"color","attrs":{"color":"#808080","name":"user"}}],"text":"文章第一次發佈於CSDN:"},{"type":"link","attrs":{"href":"https://blog.csdn.net/liuchengz_/article/details/108062139","title":null},"content":[{"type":"text","marks":[{"type":"italic"}],"text":"https://blog.csdn.net/liuchengz_/article/details/108062139"}],"marks":[{"type":"italic"},{"type":"color","attrs":{"color":"#808080","name":"user"}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"前言"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在Linux系統下編譯文件通常需要我們使用命令進行編譯,而不像時在window系統下許多編譯器可以一鍵將我們編寫的代碼編譯完成,而當我們的源文件數量很多的時候,使用Makefile進行編譯會很大程度上的提高我們的效率。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"一、Makefile是什麼?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Makefile其實就是一個文件,它默認命名爲Makefile(或者makefile),它包含了一組自動化構建工具,用來生成目標文件的指令。我的理解就是將我們平時編譯需要用到的一步步指令寫到了一個腳本文件裏,使用時只需要執行make指令就能執行Makefile中的指令。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"二、Makefile的基本格式"}]},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"target ... : prerequisites ...\n\tcommand\n\t...\n\t..."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這是一個文件的依賴關係,也就是說,target 這一個或多個的目標文件依賴於 prerequisites 中的文件,其生成規則定義在 command 中。值得注意的是,在 Makefile 中的命令,必須要以[Tab]鍵開始。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"target"}]},{"type":"text","text":"代表目標文件,即你要生成的文件,可以是中間文件也可以是最終的可執行文件。target還可以是一個Label,即一些我們自義定的操作,例如常用的clean,用於刪除指定的文件。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"prerequisites"}]},{"type":"text","text":"代表用於前面的"},{"type":"codeinline","content":[{"type":"text","text":"target"}]},{"type":"text","text":"所需要的文件。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"command"}]},{"type":"text","text":"代表make需要執行的命令,可以是任意的Shell指令。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"舉個例:我製作了一個計算器,其有加減乘除四個功能,我將其分爲了多個文件編寫,分別爲cal.h、main.c、mul.c、div.c、add.c、sub.c(舉例而已,真是的情況應該不會有人這麼做)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代碼如下(示例):"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"c"},"content":[{"type":"text","text":"calculator : main.o mul.o div.o add.o sub.o \n\tgcc main.o mul.o div.o add.o sub.o -o calculator\nmain.o : main.c cal.h\n\tgcc -c main.c\nmul.o : mmul.c cal.h\n\tgcc -c mul.c\ndiv.o : div.c cal.h\n\tgcc -c div.c\nadd.o : add.c cal.h\n\tgcc -c add.c\nsub.o : sub.c cal.h\n\tgcc -c sub.c\nclean : rm calculator main.o mul.o div.o add.o sub.o "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們將這個內容保存爲Makefile(或者makefile)然後再該目錄下輸入命令"},{"type":"codeinline","content":[{"type":"text","text":"make"}]},{"type":"text","text":"就可以生成執行文件calculator了。如果要刪除執行文件和所有的中間目標文件,只需要輸入"},{"type":"codeinline","content":[{"type":"text","text":"make clean"}]},{"type":"text","text":"就可以了,"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"三、基本結構構成"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1.變量定義"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於在Makefile中重複出現的文件,如剛纔舉例中的:main.c、main.o等文件名,我看可以將其自定義成我們所命名的變量。在Makefile中變量一般都是字符串,有點像C語言中的宏,當Makefile被執行時,其中的變量都會被擴展到相應的引用位置上。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2.顯示規則"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"make 會把其要執行的命令行在命令執行前輸出到屏幕上。當我們用“@”字符在命令行前,那麼,這個命令將不被 make 顯示出來。如果 make 執行時,帶入 make 參數“-n”或“--just-print”,那麼其只是顯示命令,但不會執行命令,這個功能可以用來調試我們的Makefile,觀察我們編寫的Makefile的執行順序。而 make 參數“-s”或“--slient”則是全面禁止命令的顯示。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"3.隱晦規則"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在我們使用 Makefile 時,有一些我們會經常使用,而且使用頻率非常高的東西,make其實是預先規定好的,其具有自動推導的功能,它可以自動推導文件以及文件依賴關係後面的命令,如.o文件由.c文件編譯而來,它們之間的依賴關係是預先就設定好的,於是我們就沒必要去在每一個.o文件後都寫上類似的命令"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"4.文件指示"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用於Makefile的嵌套執行,在大型的工程項目中,我們將不同的模塊放在不同的文件夾,然後爲每個文件夾編寫相應的Makefile,有利於我們Makefile的維護。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"5.註釋"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Makefile中只有行註釋,和UNIX的Shell腳本一樣,其註釋是用“#”字符,類似於C/C++中的“//”一樣。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"四、提高編寫效率"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在剛纔的例子中我們對6個文件進行編譯就Makefile就已經寫了13行,似乎並不比我們手動將.c文件編譯成.o目標文件然後再鏈接它們高效多少。其實再實際的工程項目中源文件遠不止此,那麼面對大量的源文件,我們可以靈活運用其基本結構中來提高我們的Makefile編寫效率。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1、預定義變量"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在Makefile中有許多變量預先就定義好了,可供我們直接調用。常用的預定義變量:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"$* "}]},{"type":"text","text":"不包含擴展名的目標文件名稱。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"$+"}]},{"type":"text","text":" 所有的依賴文件,以空格分開,並以出現的先後爲序,可能包含重複的依賴文件。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"$< "}]},{"type":"text","text":"第一個依賴文件的名稱。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"$?"}]},{"type":"text","text":" 所有的依賴文件,以空格分開,這些依賴文件的修改日期比目標的創建日期晚。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"$@"}]},{"type":"text","text":" 目標的完整名稱。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"$^"}]},{"type":"text","text":" 所有的依賴文件,以空格分開,不包含重複的依賴文件。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"$%"}]},{"type":"text","text":" 如果目標是歸檔成員,則該變量表示目標的歸檔成員名稱。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2、使用通配符"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在Makefile的編寫中我們也可以用到我們平時使用到的通配符。如:星號代表任意個任意字符,"},{"type":"codeinline","content":[{"type":"text","text":"*"}]},{"type":"text","text":".o代表文件夾中所有.o文件。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上述示例中的Make file修改後代碼示例(如下):"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"calcultor : main.o mul.o div.o add.o sub.o \n\tgcc *.o -o $@\n%.o : %.c\n\tgcc -c $< -o $@\nclean:\n\trm -f *.o calcultor"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"五、總結"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Makefile其實在我們日常的生活中編寫代碼使用到的並不多,只有在對量很大的代碼進行編譯時才能體現它的優勢,但是,學會去寫Make file對我對於語言的編譯原理上的理解會有一些幫助,所以總結了些基本的知識,希望可以幫助到大家。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"參考資料"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" - 《跟我一起寫Makefile》 作者:陳皓"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" - "},{"type":"link","attrs":{"href":"https://en.wikipedia.org/wiki/Makefile","title":""},"content":[{"type":"text","text":"Makefile"}]},{"type":"text","text":"-wikipedia"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章