浅析Linux开发工具之Makefile
一、什么是Makefile
在windows平臺下,有很多的IDE供我們使用,我們不會去考慮怎么把一個很大的工程編譯鏈接為一個可執(zhí)行程序,因為這些事IDE都為我們做了,而在Linux平臺下,我們并沒有這么高端的IDE供我們使用,所以為了在Linux平臺下能很好的編譯鏈接大型的項目,我們必須要學會使用Makefile,是否能很好的使用Makefile也從側面體現(xiàn)了一個Linux程序員是否是合格的能開發(fā)大型項目的程序員。
Makefile關系到了整個工程的編譯規(guī)則。一個工程中的源文件不計數(shù),其按類型、功能、模塊分別放在若干個目錄中,makefile定義了一系列的規(guī)則來指定,哪些文件需要先編譯,哪些文件需要后編譯,哪些文件需要重新編譯,甚至于進行更復雜的功能操作,因為makefile就像一個Shell腳本一樣,其中也可以執(zhí)行操作系統(tǒng)的命令。
makefile帶來的好處就是——“自動化編譯”,一旦寫好,只需要一個make命令,整個工程完全自動編譯,極大的提高了軟件開發(fā)的效率。make是一個命令工具,是一個解釋makefile中指令的命令工具,一般來說,大多數(shù)的IDE都有這個命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可見,makefile都成為了一種在工程方面的編譯方法。
二、Makefile的核心
Makefile最重要的兩個點就是依賴關系和與依賴關系對應的依賴方法。
1、什么是賴以關系?
前面在gcc/g++的介紹里面說了,從.c源文件到生成可執(zhí)行文件需要預處理、編譯、匯編、鏈接四個步驟,每個步驟生成的文件分別是文件預處理后的.i文件、匯編代碼.s文件、目標.o文件、可執(zhí)行文件。
所以這兒有這樣的依賴關系:
預處理的.i文件 依賴于 源文件.c文件
匯編代碼.s文件 依賴于 預處理后的.i文件
目標文件.o文件 依賴于 匯編代.s文件
可執(zhí)行文件 依賴于 目標文件.o文件
2、與依賴對應的依賴方法
這個其實很好理解,就是依賴關系中的被依賴文件怎么生成
目標文件的。
比如:
.c文件生成.i文件的過程:gcc -o file.i -E file.c
三、一個Makefile文件示例
1、源文件
頭文件:proc.h
實現(xiàn)文件:proc.c
1 #include "proc.h"2 #include <string.h>3 4 void proc()5 {6 char buf_char[101] = { 0 };7 int i = 0;8 char* action = "/_|\\";9 for(; i < 101; ++i)10 {11 buf_char[i] = '=';12 if(i < 33)13 {14 printf("\033[35m[%-101s]\033[0m %d%% %c\r", buf_char, i, action[i%4]);15 }16 else if(i < 66)17 {18 printf("\033[34m[%-101s]\033[0m %d%% %c\r", buf_char, i, action[i%4]);19 }20 else21 {22 printf("\033[32m[%-101s]\033[0m %d%% %c\r", buf_char, i, action[i%4]);23 }24 fflush(stdout);25 sleep(1);26 }27 printf("\n");28 }測試文件:test.c
1 #include "proc.h"2 3 int main()4 {5 proc();6 return 0;7 }2、Makefile文件
1 test:test.o proc.o2 gcc -o test test.o proc.o3 test.o:test.s4 gcc -o test.o -c test.s5 test.s:test.i6 gcc -o test.s -S test.i7 test.i:test.c8 gcc -o test.i -E test.c9 10 proc.o:proc.s11 gcc -o proc.o -c proc.s12 proc.s:proc.i13 gcc -o proc.s -S proc.i14 proc.i:proc.c15 gcc -o proc.i -E proc.c16 17 .PHONY:clean18 clean:19 rm -f test test.o test.s test.i proc.o proc.s proc.i其中16-19行后面會講解。
這個是自己寫的一個模擬進度條的小程序,這里需要注意的幾個點是:
1)回車和換行的區(qū)別:回車是回到行首不換行,換行是換到下一行;
2)標準輸出默認的刷新方式是行緩沖,也就是當遇到換行時,才把緩沖區(qū)里的內容打印到標準輸出上。
3)關于printf函數(shù)在終端打印輸出帶顏色的字體,可以參考:http://blog.csdn.net/lwbeyond/article/details/40588145
下面來看一看makefile的效果:
make命令執(zhí)行前,只有我們編寫好的源文件和makefile文件,我們執(zhí)行make命令后,該命令會在找名為makefile(Makefile)的文件,然后根據(jù)依賴關系依次執(zhí)行方法(具體的實現(xiàn)機制后面講)。
可以看到在我們執(zhí)行make命令后,先執(zhí)行了依賴關系對應的依賴的方法,然后生成了對應的文件。test文件就是我們要的目標文件。
程序的效果如下圖:
看到這兒也許大家會講,makefile文件的編寫也太復雜了吧,得把每一個依賴關系和依賴放法斗這么寫出來,工作量有人小,其實不然,上面的例子是為了先展示一下makefile的用法,makefile其實是可以這樣寫的:
依賴關系只有最終我們想要的目標文件和它間接依賴的文件(源文件)。
先執(zhí)行偽目標clean清空工程(關于偽目標后面會提到),然后修改Makefile內容為上述內容。
在執(zhí)行make命令,結果為:
上述倒數(shù)第四行說明這兒只執(zhí)行了一句依賴方法:gcc -o test test.c proc.c,而且只生成了一個目標文件test。執(zhí)行可執(zhí)行程序,結果與前面一致。
四、書寫規(guī)則
1、依賴關系必須是從行首開始;
2、依賴方法必須是以Tab鍵開頭。
五、Makefile的工作方式
我們要寫一個Makefile來告訴make命令如何編譯和鏈接這幾個文件。
1、編譯規(guī)則:
1)如果這個工程沒有編譯過,那么我們的所有C文件都要編譯并被鏈接。
2)如果這個工程的某幾個C文件被修改,那么我們只編譯被修改的C文件,并鏈接目標程序。
3)如果這個工程的頭文件被改變了,那么我們需要編譯引用了這幾個頭文件的C文件,并鏈接目標程序。
2、執(zhí)行機制:
1)make會在當前目錄下找名字叫“Makefile”或“makefile”的文件,沒找到即報錯;
2)如果找到,就從Makefile的頂部到底部依次讀取依賴關系、和依賴方法;
3)要是當前的依賴關系中的兩個文件都存在,則執(zhí)行它們的依賴方法,否則就繼續(xù)向下讀取,直到找到依賴關系中兩個文件都存在的地方;
4)要是一直找不到依賴關系中兩個文件都已存在的地方,就報錯,否則找到了并執(zhí)行對應依賴方法之后,檢查是否它前面的依賴關系需要的文件都已存在,是,則一層層開始向上返回,就像遞歸一樣,否,繼續(xù)向下找。
其實可以總結為Makefile是自動推導的,不需要我們去指定它怎么工作,它會自動的根據(jù)依賴關系和依賴方法去完成工作,我們只需要敲出命令make即可。
這就是整個make的依賴性,make會一層又一層地去找文件的依賴關系,直到最終編譯出第一個目標文件。
六、清理編譯的工程文件
上面例子中的16-19行:
貌似并不認識這是什么,長得奇奇怪怪的,它其實是一個我們的輔助工具,幫我們清理編譯工程文件生成的文件,方便我們對工程的重新編譯。
每個Makefile中都應該寫一個清空目標文件(.o和執(zhí)行文件)的規(guī)則,這不僅便于重編譯,也很利于保持文件的清潔。
.PHONY意思表示clean是一個“偽目標”,有什么作用呢,作用就是這個目標是一個“偽君子“,喜歡裝正經,需要我們解開它的偽裝,它才能很好的工作。
因為它是偽目標,所以make在執(zhí)行是對它視而不見,執(zhí)行到它時就停止退出。所以我們才能生成工程的編譯文件,而不是剛生就被我們的偽目標清理了。
當然,clean的規(guī)則不要放在文件的開頭,不然,這就會變成make的默認目標,相信誰也不愿意這樣。不成文的規(guī)矩是——“clean從來都是放在文件的最后”。
通過上述分析,我們知道,像clean這種,沒有被第一個目標文件直接或間接關聯(lián),那么它后面所定義的命令將不會被自動執(zhí)行,不過,我們可以顯示要make執(zhí)行。即命令——“make clean”,以此來清除所有的目標文件,以便重編譯。
總結
以上是生活随笔為你收集整理的浅析Linux开发工具之Makefile的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 初识C++之封装
- 下一篇: C语言调试技巧:stdin,stdout