浅析Linux开发工具之Makefile
一、什么是Makefile
在windows平臺(tái)下,有很多的IDE供我們使用,我們不會(huì)去考慮怎么把一個(gè)很大的工程編譯鏈接為一個(gè)可執(zhí)行程序,因?yàn)檫@些事IDE都為我們做了,而在Linux平臺(tái)下,我們并沒有這么高端的IDE供我們使用,所以為了在Linux平臺(tái)下能很好的編譯鏈接大型的項(xiàng)目,我們必須要學(xué)會(huì)使用Makefile,是否能很好的使用Makefile也從側(cè)面體現(xiàn)了一個(gè)Linux程序員是否是合格的能開發(fā)大型項(xiàng)目的程序員。
Makefile關(guān)系到了整個(gè)工程的編譯規(guī)則。一個(gè)工程中的源文件不計(jì)數(shù),其按類型、功能、模塊分別放在若干個(gè)目錄中,makefile定義了一系列的規(guī)則來指定,哪些文件需要先編譯,哪些文件需要后編譯,哪些文件需要重新編譯,甚至于進(jìn)行更復(fù)雜的功能操作,因?yàn)閙akefile就像一個(gè)Shell腳本一樣,其中也可以執(zhí)行操作系統(tǒng)的命令。
makefile帶來的好處就是——“自動(dòng)化編譯”,一旦寫好,只需要一個(gè)make命令,整個(gè)工程完全自動(dòng)編譯,極大的提高了軟件開發(fā)的效率。make是一個(gè)命令工具,是一個(gè)解釋makefile中指令的命令工具,一般來說,大多數(shù)的IDE都有這個(gè)命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可見,makefile都成為了一種在工程方面的編譯方法。
二、Makefile的核心
Makefile最重要的兩個(gè)點(diǎn)就是依賴關(guān)系和與依賴關(guān)系對(duì)應(yīng)的依賴方法。
1、什么是賴以關(guān)系?
前面在gcc/g++的介紹里面說了,從.c源文件到生成可執(zhí)行文件需要預(yù)處理、編譯、匯編、鏈接四個(gè)步驟,每個(gè)步驟生成的文件分別是文件預(yù)處理后的.i文件、匯編代碼.s文件、目標(biāo).o文件、可執(zhí)行文件。
所以這兒有這樣的依賴關(guān)系:
預(yù)處理的.i文件 依賴于 源文件.c文件
匯編代碼.s文件 依賴于 預(yù)處理后的.i文件
目標(biāo)文件.o文件 依賴于 匯編代.s文件
可執(zhí)行文件 依賴于 目標(biāo)文件.o文件
2、與依賴對(duì)應(yīng)的依賴方法
這個(gè)其實(shí)很好理解,就是依賴關(guān)系中的被依賴文件怎么生成
目標(biāo)文件的。
比如:
.c文件生成.i文件的過程:gcc -o file.i -E file.c
三、一個(gè)Makefile文件示例
1、源文件
頭文件:proc.h
實(shí)現(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 }測(cè)試文件: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行后面會(huì)講解。
這個(gè)是自己寫的一個(gè)模擬進(jìn)度條的小程序,這里需要注意的幾個(gè)點(diǎn)是:
1)回車和換行的區(qū)別:回車是回到行首不換行,換行是換到下一行;
2)標(biāo)準(zhǔn)輸出默認(rèn)的刷新方式是行緩沖,也就是當(dāng)遇到換行時(shí),才把緩沖區(qū)里的內(nèi)容打印到標(biāo)準(zhǔn)輸出上。
3)關(guān)于printf函數(shù)在終端打印輸出帶顏色的字體,可以參考:http://blog.csdn.net/lwbeyond/article/details/40588145
下面來看一看makefile的效果:
make命令執(zhí)行前,只有我們編寫好的源文件和makefile文件,我們執(zhí)行make命令后,該命令會(huì)在找名為makefile(Makefile)的文件,然后根據(jù)依賴關(guān)系依次執(zhí)行方法(具體的實(shí)現(xiàn)機(jī)制后面講)。
可以看到在我們執(zhí)行make命令后,先執(zhí)行了依賴關(guān)系對(duì)應(yīng)的依賴的方法,然后生成了對(duì)應(yīng)的文件。test文件就是我們要的目標(biāo)文件。
程序的效果如下圖:
看到這兒也許大家會(huì)講,makefile文件的編寫也太復(fù)雜了吧,得把每一個(gè)依賴關(guān)系和依賴放法斗這么寫出來,工作量有人小,其實(shí)不然,上面的例子是為了先展示一下makefile的用法,makefile其實(shí)是可以這樣寫的:
依賴關(guān)系只有最終我們想要的目標(biāo)文件和它間接依賴的文件(源文件)。
先執(zhí)行偽目標(biāo)clean清空工程(關(guān)于偽目標(biāo)后面會(huì)提到),然后修改Makefile內(nèi)容為上述內(nèi)容。
在執(zhí)行make命令,結(jié)果為:
上述倒數(shù)第四行說明這兒只執(zhí)行了一句依賴方法:gcc -o test test.c proc.c,而且只生成了一個(gè)目標(biāo)文件test。執(zhí)行可執(zhí)行程序,結(jié)果與前面一致。
四、書寫規(guī)則
1、依賴關(guān)系必須是從行首開始;
2、依賴方法必須是以Tab鍵開頭。
五、Makefile的工作方式
我們要寫一個(gè)Makefile來告訴make命令如何編譯和鏈接這幾個(gè)文件。
1、編譯規(guī)則:
1)如果這個(gè)工程沒有編譯過,那么我們的所有C文件都要編譯并被鏈接。
2)如果這個(gè)工程的某幾個(gè)C文件被修改,那么我們只編譯被修改的C文件,并鏈接目標(biāo)程序。
3)如果這個(gè)工程的頭文件被改變了,那么我們需要編譯引用了這幾個(gè)頭文件的C文件,并鏈接目標(biāo)程序。
2、執(zhí)行機(jī)制:
1)make會(huì)在當(dāng)前目錄下找名字叫“Makefile”或“makefile”的文件,沒找到即報(bào)錯(cuò);
2)如果找到,就從Makefile的頂部到底部依次讀取依賴關(guān)系、和依賴方法;
3)要是當(dāng)前的依賴關(guān)系中的兩個(gè)文件都存在,則執(zhí)行它們的依賴方法,否則就繼續(xù)向下讀取,直到找到依賴關(guān)系中兩個(gè)文件都存在的地方;
4)要是一直找不到依賴關(guān)系中兩個(gè)文件都已存在的地方,就報(bào)錯(cuò),否則找到了并執(zhí)行對(duì)應(yīng)依賴方法之后,檢查是否它前面的依賴關(guān)系需要的文件都已存在,是,則一層層開始向上返回,就像遞歸一樣,否,繼續(xù)向下找。
其實(shí)可以總結(jié)為Makefile是自動(dòng)推導(dǎo)的,不需要我們?nèi)ブ付ㄋ趺垂ぷ?#xff0c;它會(huì)自動(dòng)的根據(jù)依賴關(guān)系和依賴方法去完成工作,我們只需要敲出命令make即可。
這就是整個(gè)make的依賴性,make會(huì)一層又一層地去找文件的依賴關(guān)系,直到最終編譯出第一個(gè)目標(biāo)文件。
六、清理編譯的工程文件
上面例子中的16-19行:
貌似并不認(rèn)識(shí)這是什么,長(zhǎng)得奇奇怪怪的,它其實(shí)是一個(gè)我們的輔助工具,幫我們清理編譯工程文件生成的文件,方便我們對(duì)工程的重新編譯。
每個(gè)Makefile中都應(yīng)該寫一個(gè)清空目標(biāo)文件(.o和執(zhí)行文件)的規(guī)則,這不僅便于重編譯,也很利于保持文件的清潔。
.PHONY意思表示clean是一個(gè)“偽目標(biāo)”,有什么作用呢,作用就是這個(gè)目標(biāo)是一個(gè)“偽君子“,喜歡裝正經(jīng),需要我們解開它的偽裝,它才能很好的工作。
因?yàn)樗莻文繕?biāo),所以make在執(zhí)行是對(duì)它視而不見,執(zhí)行到它時(shí)就停止退出。所以我們才能生成工程的編譯文件,而不是剛生就被我們的偽目標(biāo)清理了。
當(dāng)然,clean的規(guī)則不要放在文件的開頭,不然,這就會(huì)變成make的默認(rèn)目標(biāo),相信誰也不愿意這樣。不成文的規(guī)矩是——“clean從來都是放在文件的最后”。
通過上述分析,我們知道,像clean這種,沒有被第一個(gè)目標(biāo)文件直接或間接關(guān)聯(lián),那么它后面所定義的命令將不會(huì)被自動(dòng)執(zhí)行,不過,我們可以顯示要make執(zhí)行。即命令——“make clean”,以此來清除所有的目標(biāo)文件,以便重編譯。
總結(jié)
以上是生活随笔為你收集整理的浅析Linux开发工具之Makefile的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 初识C++之封装
- 下一篇: linux服务器p2v,使用 Linux