版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
Makefile編寫教程目錄1.Makefile概述2.Makefile的規(guī)則3.實例4.make是如何工作的5.makefile中使用的變量6.讓make自導(dǎo)7.另類風(fēng)格的makefile8.實例一.
Makefile概述
makefile關(guān)系到了整個工程的編譯規(guī)則。一個工程中的源文件不計數(shù),其按類型、功能、模塊分別放在若干個目錄中,makefile定義了一系列的規(guī)則來指定,哪些文件需要先編譯,哪些文件需要后編譯,哪些文件需要重新編譯,甚至于進行更復(fù)雜的功能操作.makefile帶來的好處就是——“自動化編譯”,一旦寫好,只需要一個make命令,整個工程完全自動編譯,極大的提高了軟件開發(fā)的效率。make是一個命令工具,是一個解釋makefile中指令的命令工具,一般來說,大多數(shù)的IDE都有這個命令,比如:Delphi的
make,Visual
C++的make,Linux下GNU的make??梢?,makefile都成為了一種在工程方面的編譯方法1.源程序的編譯
在Linux下面,如果要編譯一個C語言源程序,我們要使用GNU的gcc編譯器.下面我們以一個實例來說明如何使用gcc編譯器.假設(shè)我們有下面一個非常簡單的源程序(hello.c):intmain(intargc,char**argv){printf("HelloLinux\n");}要編譯這個程序,我們只要在命令行下執(zhí)行:gcc-ohellohello.cgcc編譯器就會為我們生成一個hello的可執(zhí)行文件.執(zhí)行./hello就可以看到程序的輸出結(jié)果了.命令行中g(shù)cc表示我們是用gcc來編譯我們的源程序,-o選項表示我們要求編譯器給我們輸出的可執(zhí)行文件名為hello而hello.c是我們的源程序文件.gcc編譯器有許多選項,一般來說我們只要知道其中的幾個就夠了.(1)-o選項我們已經(jīng)知道了,表示我們要求輸出的可執(zhí)行文件名.(2)-c選項表示我們只要求編譯器輸出目標(biāo)代碼,而不必要輸出可執(zhí)行文件.(3)-g選項表示我們要求編譯器在編譯的時候提供我們以后對程序進行調(diào)試的信息.知道了這三個選項,我們就可以編譯我們自己所寫的簡單的源程序了,如果你想要知道更多的選項,可以查看gcc的幫助文檔,那里有著許多對其它選項的詳細(xì)說明.2.為什么需要Makefile文件
假設(shè)我們有下面這樣的一個程序,源代碼如下:/*main.c*/#include"mytool1.h"#include"mytool2.h"intmain(intargc,char**argv){mytool1_print("hello");mytool2_print("hello");}/*mytool1.h*/#ifndef_MYTOOL_1_H#define_MYTOOL_1_Hvoidmytool1_print(char*print_str);#endif/*mytool1.c*/#include"mytool1.h"voidmytool1_print(char*print_str){printf("Thisismytool1print%s\n",print_str);}/*mytool2.h*/#ifndef_MYTOOL_2_H#define_MYTOOL_2_Hvoidmytool2_print(char*print_str);#endif/*mytool2.c*/#include"mytool2.h"voidmytool2_print(char*print_str){printf("Thisismytool2print%s\n",print_str);}當(dāng)然由于這個程序是很短的我們可以這樣來編譯gcc-cmain.cgcc-cmytool1.cgcc-cmytool2.cgcc-omainmain.omytool1.omytool2.o這樣的話我們也可以產(chǎn)生main程序,而且也不是很麻煩.但是如果我們考慮一下如果有一天我們修改了其中的一個文件(比如說mytool1.c)那么我們難道還要重新輸入上面的命令?或者我們的程序有幾百個源程序的時候,難道也要編譯器重新一個一個的去編譯?為此,聰明的程序員們想出了一個很好的工具來做這件事情,這就是make.我們只要執(zhí)行以下make,就可以把上面的問題解決掉.在我們執(zhí)行make之前,我們要先編寫一個非常重要的文件.--Makefile.3.關(guān)于程序的編譯和鏈接
在此,我想多說關(guān)于程序編譯的一些規(guī)范和方法,一般來說,無論是C、C++、還是pas,首先要把源文件編譯成中間代碼文件,在Windows下也就是
.obj
文件,UNIX下是
.o
文件,即
Object
File,這個動作叫做編譯(compile)。然后再把大量的Object
File合成執(zhí)行文件,這個動作叫作鏈接(link)。
編譯時,編譯器需要的是語法的正確,函數(shù)與變量的聲明的正確。對于后者,通常是你需要告訴編譯器頭文件的所在位置(頭文件中應(yīng)該只是聲明,而定義應(yīng)該放在C/C++文件中),只要所有的語法正確,編譯器就可以編譯出中間目標(biāo)文件。一般來說,每個源文件都應(yīng)該對應(yīng)于一個中間目標(biāo)文件(O文件或是
OBJ文件)。鏈接時,主要是鏈接函數(shù)和全局變量,所以,我們可以使用這些中間目標(biāo)文件(O文件或是OBJ文件)來鏈接我們的應(yīng)用程序。鏈接器并不管函數(shù)所在的源文件,只管函數(shù)的中間目標(biāo)文件(Object
File),在大多數(shù)時候,由于源文件太多,編譯生成的中間目標(biāo)文件太多,而在鏈接時需要明顯地指出中間目標(biāo)文件名,這對于編譯很不方便,所以,我們要給中間目標(biāo)文件打個包,在Windows下這種包叫“庫文件”(Library
File),也就是
.lib
文件,在UNIX下,是Archive
File,也就是
.a
文件??偨Y(jié)一下,源文件首先會生成中間目標(biāo)文件,再由中間目標(biāo)文件生成執(zhí)行文件。在編譯時,編譯器只檢測程序語法,和函數(shù)、變量是否被聲明。如果函數(shù)未被聲明,編譯器會給出一個警告,但可以生成Object
File。而在鏈接程序時,鏈接器會在所有的Object
File中找尋函數(shù)的實現(xiàn),如果找不到,那就會報鏈接錯誤碼(Linker
Error),在VC下,這種錯誤一般是:Link
2001錯誤,意思說是說,鏈接器未能找到函數(shù)的實現(xiàn)。你需要指定函數(shù)的Object
File.4.Makefile
介紹make命令執(zhí)行時,需要一個Makefile文件,以告訴make命令需要怎么樣的去編譯和鏈接程序。首先,我們用一個示例來說明Makefile的書寫規(guī)則。以便給大家一個感性認(rèn)識。這個示例來源于GNU的make使用手冊,在這個示例中,我們的工程有8個C文件,和3個頭文件,我們要寫一個Makefile來告訴make命令如何編譯和鏈接這幾個文件。我們的規(guī)則是:(1)如果這個工程沒有編譯過,那么我們的所有C文件都要編譯并被鏈接。(2)如果這個工程的某幾個C文件被修改,那么我們只編譯被修改的C文件,并鏈接目標(biāo)程序。(3)如果這個工程的頭文件被改變了,那么我們需要編譯引用了這幾個頭文件的C文件,并鏈接目標(biāo)程序。二、Makefile的規(guī)則在講述這個Makefile之前,還是讓我們先來粗略地看一看Makefile的規(guī)則。target...:mand......target也就是一個目標(biāo)文件,可以是ObjectFile,也可以是執(zhí)行文件,還可以是一個標(biāo)簽(Label)。prerequisites是要生成那個target所需要的文件或是目標(biāo)。command是make需要執(zhí)行的命令。(任意的Shell命令)注意:(1)每一行命令行的行首必須是一個跳格字符(即tab)(2)行首是空格無效,執(zhí)行makefile會出錯(3)如果命令行過長,可用\分行,分行后的新行,無需使用tab打頭這是一個文件的依賴關(guān)系,也就是說,target這一個或多個的目標(biāo)文件依賴于prerequisites中的文件,其生成規(guī)則定義在command中。說白一點就是說,prerequisites中如果有一個以上的文件比target文件要新的話,command所定義的命令就會被執(zhí)行。這就是Makefile的規(guī)則,也就是Makefile中最核心的內(nèi)容。例一:#這是第一章那個程序的Makefile文件
main:main.omytool1.omytool2.ogcc-omainmain.omytool1.omytool2.omain.o:main.cmytool1.hmytool2.hgcc-cmain.cmytool1.o:mytool1.cmytool1.hgcc-cmytool1.cmytool2.o:mytool2.cmytool2.hgcc-cmytool2.c有了這個Makefile文件,如果我們什么時候修改了源程序當(dāng)中的什么文件,我們只要執(zhí)行make命令,我們的編譯器都只會去編譯和我們修改的文件有關(guān)的文件,其它的文件她連理都不想去理的.三.實例下面我們學(xué)習(xí)Makefile是如何編寫的:在Makefile中以#開始的行都是注釋行.Makefile中最重要的是描述文件的依賴關(guān)系的說明.第一行表示的是依賴關(guān)系.第二行是規(guī)則.比如說我們上面的那個Makefile文件的第二行main:main.omytool1.omytool2.o表示我們的目標(biāo)(target)main的依賴對象(components)是main.omytool1.omytool2.o當(dāng)依賴的對象在目標(biāo)修改的話,就要去執(zhí)行規(guī)則一行所指定的命令.就象我們上面那個Makefile第二行所說的一樣要執(zhí)行g(shù)cc-omainmain.omytool1.omytool2.oMakefile有三個非常有用的變量.分別是$@,$^,$<代表的意義分別是:$@--目標(biāo)文件,$^--所有的依賴文件,$<--第一個依賴文件.如果我們使用上面三個變量,那么我們可以簡化我們的Makefile文件為:#這是簡化后的Makefile
main:main.omytool1.omytool2.ogcc-o$@$^main.o:main.cmytool1.hmytool2.hgcc-c$<mytool1.o:mytool1.cmytool1.hgcc-c$<mytool2.o:mytool2.cmytool2.hgcc-c$<經(jīng)過簡化后我們的Makefile是簡單了一點,不過人們有時候還想簡單一點.這里我們學(xué)習(xí)一個Makefile的缺省規(guī)則..c.o:gcc-c$<這個規(guī)則表示所有的.o文件都是依賴與相應(yīng)的.c文件的.例如mytool.o依賴于mytool.c這樣Makefile還可以變?yōu)?#這是再一次簡化后的Makefile
main:main.omytool1.omytool2.ogcc-o$@$^..c.o:gcc-c$<
例二:正如前面所說的,如果一個工程有3個頭文件,和8個C文件,我們?yōu)榱送瓿汕懊嫠龅哪侨齻€規(guī)則,我們的Makefile應(yīng)該是下面的這個樣子的。edit:main.okbd.ocommand.odisplay.o/insert.osearch.ofiles.outils.ogcc-oeditmain.okbd.ocommand.odisplay.o/insert.osearch.ofiles.outils.omain.o:main.cdefs.hgcc-cmain.ckbd.o:kbd.cdefs.hcommand.hgcc-ckbd.ccommand.o:command.cdefs.hcommand.hgcc-ccommand.cdisplay.o:display.cdefs.hbuffer.hgcc-cdisplay.cinsert.o:insert.cdefs.hbuffer.hgcc-cinsert.csearch.o:search.cdefs.hbuffer.hgcc-csearch.cfiles.o:files.cdefs.hbuffer.hcommand.h
gcc-cfiles.cutils.o:utils.cdefs.hgcc-cutils.cclean:rmeditmain.okbd.ocommand.odisplay.o/insert.osearch.ofiles.outils.o反斜杠(/)是換行符的意思。這樣比較便于Makefile的易讀。我們可以把這個內(nèi)容保存在文件為“Makefile”或“makefile”的文件中,然后在該目錄下直接輸入命令“make”就可以生成執(zhí)行文件edit。如果要刪除執(zhí)行文件和所有的中間目標(biāo)文件,那么,只要簡單地執(zhí)行一下“makeclean”就可以了。在這個makefile中,目標(biāo)文件(target)包含:執(zhí)行文件edit和中間目標(biāo)文件(*.o),依賴文件(prerequisites)就是冒號后面的那些.c文件和.h文件。每一個.o文件都有一組依賴文件,而這些.o文件又是執(zhí)行文件edit的依賴文件。依賴關(guān)系的實質(zhì)上就是說明了目標(biāo)文件是由哪些文件生成的,換言之,目標(biāo)文件是哪些文件更新的。在定義好依賴關(guān)系后,后續(xù)的那一行定義了如何生成目標(biāo)文件的操作系統(tǒng)命令,一定要以一個Tab鍵作為開頭。記住,make并不管命令是怎么工作的,他只管執(zhí)行所定義的命令。make會比較targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期要比targets文件的日期要新,或者target不存在的話,那么,make就會執(zhí)行后續(xù)定義的命令。這里要說明一點的是,clean不是一個文件,它只不過是一個動作名字,有點像C語言中的lable一樣,其冒號后什么也沒有,那么,make就不會自動去找文件的依賴性,也就不會自動執(zhí)行其后所定義的命令。要執(zhí)行其后的命令,就要在make命令后明顯得指出這個lable的名字。這樣的方法非常有用,我們可以在一個makefile中定義不用的編譯或是和編譯無關(guān)的命令,比如程序的打包,程序的備份,等等。四.make是如何工作的在默認(rèn)的方式下,也就是我們只輸入make命令。那么,1、make會在當(dāng)前目錄下找名字叫“Makefile”或“makefile”的文件。2、如果找到,它會找文件中的第一個目標(biāo)文件(target),在上面的例二中,他會找到“edit”這個文件,并把這個文件作為最終的目標(biāo)文件。3、如果edit文件不存在,或是edit所依賴的后面的.o文件的文件修改時間要比edit這個文件新,那么,他就會執(zhí)行后面所定義的命令來生成edit這個文件。4、如果edit所依賴的.o文件也不存在,那么make會在當(dāng)前文件中找目標(biāo)為.o文件的依賴性,如果找到則再根據(jù)那一個規(guī)則生成.o文件。(這有點像一個堆棧的過程)5、當(dāng)然,你的C文件和H文件是存在的啦,于是make會生成.o文件,然后再用.o文件生命make的終極任務(wù),也就是可執(zhí)行文件edit了。這就是整個make的依賴性,make會一層又一層地去找文件的依賴關(guān)系,直到最終編譯出第一個目標(biāo)文件。在找尋的過程中,如果出現(xiàn)錯誤,比如最后被依賴的文件找不到,那么make就會直接退出,并報錯,而對于所定義的命令的錯誤,或是編譯不成功,make根本不理。make只管文件的依賴性,即,如果在我找了依賴關(guān)系之后,冒號后面的文件還是不在,那么對不起,我就不工作啦。通過上述分析,我們知道,像clean這種,沒有被第一個目標(biāo)文件直接或間接關(guān)聯(lián),那么它后面所定義的命令將不會被自動執(zhí)行,不過,我們可以顯示要make執(zhí)行。即命令——“makeclean”,以此來清除所有的目標(biāo)文件,以便重編譯。于是在我們編程中,如果這個工程已被編譯過了,當(dāng)我們修改了其中一個源文件,比如file.c,那么根據(jù)我們的依賴性,我們的目標(biāo)file.o會被重編譯(也就是在這個依性關(guān)系后面所定義的命令),于是file.o的文件也是最新的啦,于是file.o的文件修改時間要比edit要新,所以edit也會被重新鏈接了。而如果我們改變了“command.h”,那么,kdb.o、command.o和files.o都會被重編譯,并且,edit會被重鏈接。五.makefile中使用的變量在上面的例子中,先讓我們看看edit的規(guī)則:
edit:main.okbd.ocommand.odisplay.o/insert.osearch.ofiles.outils.ogcc-oeditmain.okbd.ocommand.odisplay.o/insert.osearch.ofiles.outils.o我們可以看到[.o]文件的字符串被重復(fù)了兩次,如果我們的工程需要加入一個新的[.o]文件,那么我們需要在兩個地方加(應(yīng)該是三個地方,還有一個地方在clean中)。當(dāng)然,我們的makefile并不復(fù)雜,所以在兩個地方加也不累,但如果makefile變得復(fù)雜,那么我們就有可能會忘掉一個需要加入的地方,而導(dǎo)致編譯失敗。所以,為了makefile的易維護,在makefile中我們可以使用變量。makefile的變量也就是一個字符串,理解成C語言中的宏可能會更好。
比如,我們聲明一個變量,叫objects,OBJECTS,objs,OBJS,obj,或是OBJ,反正不管什么啦,只要能夠表示obj文件就行了。我們在makefile一開始就這樣定義:objects=main.okbd.ocommand.odisplay.o/insert.osearch.ofiles.outils.o于是,我們就可以很方便地在我們的makefile中以“$(objects)”的方式來使用這個變量了,于是我們的改良版makefile就變成下面這個樣子:
objects=main.okbd.ocommand.odisplay.o/insert.osearch.ofiles.outils.oedit:$(objects)gcc-oedit$(objects)main.o:main.cdefs.hgcc-cmain.ckbd.o:kbd.cdefs.hcommand.hgcc-ckbd.ccommand.o:command.cdefs.hcommand.h
gcc-ccommand.cdisplay.o:display.cdefs.hbuffer.hgcc-cdisplay.cinsert.o:insert.cdefs.hbuffer.hgcc-cinsert.csearch.o:search.cdefs.hbuffer.hgcc-csearch.cfiles.o:files.cdefs.hbuffer.hcommand.hgcc-cfiles.cutils.o:utils.cdefs.hgcc-cutils.cclean:rmedit$(objects)于是如果有新的.o文件加入,我們只需簡單地修改一下objects變量就可以了。六.讓make自動推導(dǎo)GNU的make很強大,它可以自動推導(dǎo)文件以及文件依賴關(guān)系后面的命令,于是我們就沒必要去在每一個[.o]文件后都寫上類似的命令,因為,我們的make會自動識別,并自己推導(dǎo)命令。只要make看到一個[.o]文件,它就會自動的把[.c]文件加在依賴關(guān)系中,如果make找到一個whatever.o,那么whatever.c,就會是whatever.o的依賴文件。并且gcc-cwhatever.c也會被推導(dǎo)出來,于是,我們的makefile再也不用寫得這么復(fù)雜。我們的是新的makefile可以寫成:
objects=main.okbd.ocommand.odisplay.o/insert.osearch.ofiles.outils.oedit:$(objects)gcc-oedit$(objects)main.o:defs.hkbd.o:defs.hcommand.hcommand.o:defs.hcommand.hdisplay.o:defs.hbuffer.hinsert.o:defs.hbuffer.hsearch.o:defs.hbuffer.hfiles.o:defs.hbuffer.hcommand.hutils.o:defs.h.PHONY:cleanclean:rmedit$(objects)這種方法,也就是make的“隱晦規(guī)則”。上面文件內(nèi)容中,“.PHONY”表示,clean是個偽目標(biāo)文件。七.另類風(fēng)格的makefile
即然我們的make可以自動推導(dǎo)命令,那么我看到那堆[.o]和[.h]的依賴就有點不爽,那么多的重復(fù)的[.h],能不能把其收攏起來,好吧,沒有問題,這個對于make來說很容易,誰叫它提供了自動推導(dǎo)命令和文件的功能呢?來看看最新風(fēng)格的makefile吧。
objects=main.okbd.ocommand.odisplay.o/insert.osearch.ofiles.outils.oedit:$(objects)gcc-oedit$(objects)$(objects):defs.hkbd.ocommand.ofiles.o:command.hdisplay.oinsert.osearch.ofiles.o:buffer.h
.PHONY:cleanclean:rmedit$(objects)這種風(fēng)格,讓我們的makefile變得很簡單,但我們的文件依賴關(guān)系就顯得有點凌亂了。魚和熊掌不可兼得。還看你的喜好了。我是不喜歡這種風(fēng)格的,一是文件的依賴關(guān)系看不清楚,二是如果文件一多,要加入幾個新的.o文件,那就理不清楚了。更多內(nèi)容請參見《Linux環(huán)境下的C編程指南》八.實
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025版兒童托管所合伙人經(jīng)營管理協(xié)議示范文本3篇
- 二零二五版新能源汽車電池回收利用服務(wù)協(xié)議4篇
- 二零二五年度打樁工程信息化管理合同規(guī)范范本3篇
- 2025年鮮蛋電商運營與數(shù)據(jù)分析合作協(xié)議3篇
- 二零二五年礦山承包經(jīng)營資源節(jié)約利用協(xié)議3篇
- 2025年度煤礦企業(yè)員工勞動合同范本(含加班補貼計算標(biāo)準(zhǔn))4篇
- 基于二零二五年度技術(shù)的香港電子合同制造成本降低協(xié)議3篇
- 個人電商運營服務(wù)合同2024年度3篇
- erp合同管理系統(tǒng)
- 2025年度無人機精準(zhǔn)定位服務(wù)采購合同文本3篇
- 2025年上半年江蘇連云港灌云縣招聘“鄉(xiāng)村振興專干”16人易考易錯模擬試題(共500題)試卷后附參考答案
- DB3301T 0382-2022 公共資源交易開評標(biāo)數(shù)字見證服務(wù)規(guī)范
- 人教版2024-2025學(xué)年八年級上學(xué)期數(shù)學(xué)期末壓軸題練習(xí)
- 江蘇省無錫市2023-2024學(xué)年八年級上學(xué)期期末數(shù)學(xué)試題(原卷版)
- 俄語版:中國文化概論之中國的傳統(tǒng)節(jié)日
- 2022年湖南省公務(wù)員錄用考試《申論》真題(縣鄉(xiāng)卷)及答案解析
- 婦科一病一品護理匯報
- 2024年全國統(tǒng)一高考數(shù)學(xué)試卷(新高考Ⅱ)含答案
- 移動商務(wù)內(nèi)容運營(吳洪貴)任務(wù)四 引起受眾傳播內(nèi)容要素的掌控
- 繪本《汪汪的生日派對》
- 助產(chǎn)護理畢業(yè)論文
評論
0/150
提交評論