Makefile詳解

有感于網(wǎng)絡(luò)上很多技術(shù)博客的排版方式不夠統(tǒng)一滚秩,并趨向于隨意专执,影響學(xué)習(xí)的效率和動(dòng)力,故而根據(jù)自己的理解將其重新編排如下郁油,不算原創(chuàng)本股,算作是自己的學(xué)習(xí)心得吧,也可供自己日后翻看桐腌。

一個(gè)Makefile例子

make 命令執(zhí)行時(shí)拄显,需要根據(jù)一些規(guī)則來決定按照怎么樣的方式去編譯和鏈接程序,這些規(guī)則就由 makefile 文件所指定案站。如果我們 makefile 文件寫的足夠好躬审,make 命令會(huì)自動(dòng)地根據(jù)當(dāng)前的文件修改的情況來確定哪些文件需要重編譯,從而自己編譯所需要的文件和鏈接目標(biāo)程序蟆盐。

首先承边,本文將給出一個(gè)makefile文件的示例,以便大家能有一個(gè)直觀感受舱禽,這個(gè)例子來源于GNU的make使用手冊(cè)炒刁。在這個(gè)例子中恩沽,我們的工程有8個(gè)c文件誊稚,和3個(gè)頭文件,我們要寫一個(gè)makefile來告訴make命令如何編譯和鏈接這幾個(gè)文件。例子如下:

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

這個(gè)例子里 make 的編碼規(guī)則如下:

a. 如果這個(gè)工程沒有編譯過里伯,那么我們的所有c文件都要編譯并被鏈接城瞎。
b. 如果這個(gè)工程的某幾個(gè)c文件被修改,那么我們只編譯被修改的c文件疾瓮,并鏈接目標(biāo)程序脖镀。
c. 如果這個(gè)工程的頭文件被改變了,那么我們需要編譯引用了這幾個(gè)頭文件的c文件狼电,并鏈接目標(biāo)程序蜒灰。

Makefile規(guī)則

在詳細(xì)拆解上一節(jié)的 Makefile 之前,先來看下 Makefile 的基本范式肩碟。

target ... :prerequisites ...
command
...

target可以是一個(gè) 1) object file(可執(zhí)行文件)强窖,2) 可執(zhí)行文件,還可以是個(gè)3) label(標(biāo)簽)削祈,關(guān)于標(biāo)簽這個(gè)特性翅溺,在后面的偽目標(biāo)章節(jié)還會(huì)有敘述。

prerequisites 就是髓抑,要生成那個(gè)target所需要的文件或是目標(biāo)咙崎。command 也就是 make 需要執(zhí)行的命令,可以是任意的
shell 命令吨拍。

這是一個(gè)文件的依賴關(guān)系褪猛,也就是說,target 這一個(gè)或多個(gè)的目標(biāo)文件依賴于 prerequisites 中的文件羹饰,其生成規(guī)則定義在 command中握爷。同時(shí),prerequisites 中如果有一個(gè)以上的文件比target文件要新的話严里,command 所定義的命令就會(huì)被執(zhí)行新啼。這就是Makefile的規(guī)則,也是 Makefile最核心的內(nèi)容刹碾。

有了這些規(guī)則后燥撞,再來分析上面的例子。在這個(gè) makefile 中迷帜,目標(biāo)文件(target)包含:

  • 執(zhí)行文件edit
  • 中間目標(biāo)文件(*.o)

依賴文件(prerequisites)就是冒號(hào)后面的那些 .c 文件和 .h文件物舒。每一個(gè) .o文件都有一組依賴文件,而這些 .o文件又是執(zhí)行文件 edit 的依賴文件戏锹。

在定義好依賴關(guān)系后冠胯,后續(xù)的那一行定義了如何生成目標(biāo)文件的系統(tǒng)命令,一定要以一個(gè)tab鍵作為開頭锦针。make會(huì)比較
targets 文件和 prerequisites 文件的修改日期荠察,如果 prerequisites 文件的日期要比targets文件的日期要新置蜀,或者 target 不存在的話,那么悉盆,make就會(huì)執(zhí)行后續(xù)定義的命令盯荤。

我們可以把這個(gè)內(nèi)容保存在名字為makefileMakefile的文件中,然后在該目錄下直接輸入命令 make 就可以生成可執(zhí)行文件edit焕盟。如果要?jiǎng)h除執(zhí)行文件和所有的中間目標(biāo)文件秋秤,那么,只要簡(jiǎn)單地執(zhí)行一下 make clean就可以了脚翘。注:反斜線(\)是換行符的意思灼卢,這樣比較便于閱讀。

這里要說明一點(diǎn)的是来农,clean 不是一個(gè)文件芥玉,它只不過是一個(gè)動(dòng)作名字,有點(diǎn)像C語言中的 lable 一樣备图,其冒號(hào)后什么也沒有灿巧,那么,make就不會(huì)去找它的依賴性揽涮,也就不會(huì)自動(dòng)執(zhí)行其后所定義的命令抠藕。要執(zhí)行其后的命令(不僅用于 clean,其他 lable 同樣適用)蒋困,就要在 make 命令后顯式指出這個(gè) lable 的名字盾似。這樣的方法非常有用,我們可以在一個(gè) makefile 中定義不用的編譯或是和編譯無關(guān)的命令雪标,比如程序的打包零院,程序的備份,等等村刨。

Make是如何工作的

在默認(rèn)的方式下告抄,也就是我們只輸入make命令。那么嵌牺,

  1. make 會(huì)在當(dāng)前目錄下找名字叫Makefilemakefile的文件打洼。
  2. 如果找到,它會(huì)找文件中的第一個(gè)目標(biāo)文件(target)逆粹,在上面的例子中募疮,它會(huì)找到 edit 這個(gè)文件,并把這個(gè)文件作為最終的目標(biāo)文件僻弹。
  3. 如果 edit 文件不存在阿浓,或是 edit 所依賴的后面的.o文件的文件修改時(shí)間要比 edit 這個(gè)文件新,那么蹋绽,它就會(huì)執(zhí)行后面所定義的命令來生成 edit 這個(gè)文件芭毙。
  4. 如果 edit 所依賴的.o文件也不存在筋蓖,那么 make 會(huì)在當(dāng)前文件中找目標(biāo)為.o文件的依賴性,如果找到則再根據(jù)那一個(gè)規(guī)則生成.o文件稿蹲。(有點(diǎn)像是堆棧的過程)
  5. 當(dāng)然扭勉,你的.c文件和.h文件是存在的啦鹊奖,于是 make 會(huì)生成 .o 文件苛聘,然后再用.o文件生成 make 的終極任務(wù),也就是執(zhí)行文件 edit 了忠聚。

這就是整個(gè) make 的依賴性设哗,make 會(huì)一層又一層地去找文件的依賴關(guān)系,直到最終編譯出第一個(gè)目標(biāo)文件两蟀。在找尋的過程中网梢,如果出現(xiàn)錯(cuò)誤,比如最后被依賴的文件找不到赂毯,那么make就會(huì)直接退出战虏,并報(bào)錯(cuò),而對(duì)于所定義的命令的錯(cuò)誤党涕,或是編譯不成功烦感,這些都不在 make 職責(zé)范圍內(nèi)。

通過上述分析膛堤,我們知道手趣,像 clean 這種,沒有被第一個(gè)目標(biāo)文件直接或間接關(guān)聯(lián)肥荔,那么它后面所定義的命令將不會(huì)被自動(dòng)執(zhí)行绿渣,不過,我們可以顯示要 make 執(zhí)行燕耿。即命令make clean中符,以此來清除所有的目標(biāo)文件,以便重編譯誉帅。

在Makefile中使用變量

在上面的例子中可以看到舟茶,后綴為.o的一大串文件名寫了兩次,這樣比較費(fèi)時(shí)費(fèi)力堵第,而且如果文件有所增減吧凉,要修改的地方也非常多,對(duì)以后的維護(hù)造成困難踏志。在這種情形下阀捅,我們可以在Makefile里使用變量代替這一大串依賴文件,這里變量的使用方式基本類似于shell腳本里變量的使用方法针余。

我們可以在makefile一開始就這樣定義:

objects = main.o kbd.o command.o display.o \
        insert.o search.o files.o utils.o

那么接下來我們就可以很方便地在我們的Makefile中以$(objects)的方式來使用這個(gè)變量了饲鄙,于是如果有新的.o 文件加入凄诞,我們只需簡(jiǎn)單地修改一下 objects 變量就可以了。

讓 make 自動(dòng)推導(dǎo)

GNU的 make 很強(qiáng)大忍级,它可以自動(dòng)推導(dǎo)文件以及文件依賴關(guān)系后面的命令帆谍,于是我們就沒必要去在每一個(gè).o文件后都寫上類似的命令。因?yàn)橹嵩郏覀兊膍ake會(huì)自動(dòng)識(shí)別汛蝙,并自己推導(dǎo)命令。

只要make看到一個(gè).o文件朴肺,它就會(huì)自動(dòng)的把.c文件加在依賴關(guān)系中窖剑,如果make找到一個(gè)FILENAME.o,那么 FILENAME.c戈稿,就會(huì)是FILENAME.o的依賴文件西土。并且 cc -c FILENAME.c 也會(huì)被推導(dǎo)出來,于是鞍盗,我們的makefile 再也不用寫得這么復(fù)雜需了。我們的新makefile就可以這么寫了。

objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o
cc = gcc

edit: $(objects)
      cc -o edit $(objects)

main.o: defs.h
kbd.o: defs.h command.h
command.o: defs.h command.h
display.o: defs.h buffer.h
insert.o: defs.h buffer.h
search.o: defs.h buffer.h
files.o: defs.h buffer.h command.h
utils.o: defs.h

.PHONY: clean
clean:
    rm edit $(objects)

這種方法般甲,也就是make的**肋乍。上面文件內(nèi)容中,“.PHONY”表示欣除,clean是個(gè)偽目標(biāo)文件住拭。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市历帚,隨后出現(xiàn)的幾起案子滔岳,更是在濱河造成了極大的恐慌,老刑警劉巖挽牢,帶你破解...
    沈念sama閱讀 212,029評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谱煤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡禽拔,警方通過查閱死者的電腦和手機(jī)刘离,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來睹栖,“玉大人硫惕,你說我怎么就攤上這事∫袄矗” “怎么了恼除?”我有些...
    開封第一講書人閱讀 157,570評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我豁辉,道長(zhǎng)令野,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,535評(píng)論 1 284
  • 正文 為了忘掉前任徽级,我火速辦了婚禮气破,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘餐抢。我一直安慰自己现使,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評(píng)論 6 386
  • 文/花漫 我一把揭開白布弹澎。 她就那樣靜靜地躺著朴下,像睡著了一般努咐。 火紅的嫁衣襯著肌膚如雪苦蒿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,850評(píng)論 1 290
  • 那天渗稍,我揣著相機(jī)與錄音佩迟,去河邊找鬼。 笑死竿屹,一個(gè)胖子當(dāng)著我的面吹牛报强,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拱燃,決...
    沈念sama閱讀 39,006評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼秉溉,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了碗誉?” 一聲冷哼從身側(cè)響起召嘶,我...
    開封第一講書人閱讀 37,747評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎哮缺,沒想到半個(gè)月后弄跌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡尝苇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評(píng)論 2 327
  • 正文 我和宋清朗相戀三年铛只,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糠溜。...
    茶點(diǎn)故事閱讀 38,683評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡淳玩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出非竿,到底是詐尸還是另有隱情蜕着,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評(píng)論 4 330
  • 正文 年R本政府宣布汽馋,位于F島的核電站侮东,受9級(jí)特大地震影響圈盔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜悄雅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評(píng)論 3 315
  • 文/蒙蒙 一驱敲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宽闲,春花似錦众眨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至览徒,卻和暖如春狈定,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背习蓬。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評(píng)論 1 266
  • 我被黑心中介騙來泰國打工纽什, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人躲叼。 一個(gè)月前我還...
    沈念sama閱讀 46,401評(píng)論 2 360
  • 正文 我出身青樓芦缰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親枫慷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子让蕾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • makefile關(guān)系到整個(gè)工程的編譯規(guī)則,一個(gè)工程中的源文件不計(jì)其數(shù)或听,按其類型探孝、功能、模塊分別放在若干的目錄當(dāng)中神帅,...
    Joe_HUST閱讀 1,876評(píng)論 0 3
  • 由于用的是Chrome再姑,上一篇的末尾不知道為何突然退出,點(diǎn)進(jìn)去好多次找御,依然是一有動(dòng)作就自動(dòng)退出元镀。之前用插件馬克飛象...
    神的第57個(gè)名字閱讀 505評(píng)論 0 2
  • 來自陳浩的一片老文,但絕對(duì)營養(yǎng)霎桅。 示例工程:3 個(gè)頭文件*.h栖疑,和 8 個(gè) C 文件*.c。 初 編譯過程滔驶,源文件...
    周筱魯閱讀 4,690評(píng)論 0 17
  • @(linux 編程)[開發(fā)技能, 工具使用] What is GNU Make Make 是控制工程中通過源碼生...
    orientlu閱讀 11,325評(píng)論 0 26
  • makefile的規(guī)則 組成 target prerequisites commandtarget這一個(gè)或多個(gè)的目...
    Neucrack閱讀 2,749評(píng)論 0 3