|
make和makefile入門 本文講述的是簡單的make和makefile基礎(chǔ)知識,幫助大家了解minix的boot目錄下 的makefile文件,還要求大家先了解linux下的一些常見命令。 make的作者:Richard Stallman and Roland McGrath GNU make滿足POSIX.2的標(biāo)準(zhǔn)。 如果想執(zhí)行make命令,首先編寫一個makefile文件,該文件主要是描述你的 程序中所有文件的關(guān)系以及你所用的命令(編譯命令等)。在一個程序中,可執(zhí)行文 件是從目標(biāo)文件升級(update)而來。如果你創(chuàng)建了一個合適的makefile文件,當(dāng)你 改變了部分源文件內(nèi)容時,你可通過執(zhí)行make命令來重新編譯。 make程序通過使用makefile作為配置文件,通過檢測文件的更新時間,來決 定哪些文件需要重新編譯。你也可以通過給make命令帶命令行參數(shù)來決定那些文件 需要重新編譯。一般,默認(rèn)使用makefile文件來告訴make命令如何編譯和鏈接程序。 makefile的常見語法規(guī)則: 1. target ... : dependencies ... command ... ... target一般為程序所生成的文件名。例如,是可執(zhí)行文件名或目標(biāo)文件名;一 個目標(biāo)也可以是一個將要執(zhí)行的動作的名稱,見下例中的clean。 dependencies就是作為輸入文件,被用來生成目標(biāo)文件。一個目標(biāo)文件可以由 好幾個輸入文件編譯而成。 command就是make所執(zhí)行的動作,可以由好幾個命令組成,每個命令獨占一行。 注意,每個命令行開頭必須有一個Tab鍵,千萬不要忘記。 通常,命令是用來編譯輸入文件以生成目標(biāo)文件的。當(dāng)然,命令也可以不需要 任何依賴(dependencies)。除了上述語法規(guī)則模塊,一個makefile文件可能還包 含其他內(nèi)容。 2.一個簡單的makefile文件的分析: 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 解析,\為續(xù)行符。edit目標(biāo)文件依賴main.o、kbd.o、command.o、 display.o、insert.o、search.o、files.o和utils.o等八個文件,并通 過隨后的CC命令編譯而成,其它類似。執(zhí)行make命令即可生成edit可執(zhí)行文件或 上述八個.o文件。執(zhí)行make clean命令可刪除edit可執(zhí)行文件和上 述八個.o文件。 make命令并不在乎你使用什么編譯命令(它由你來決定),它只在乎文 件之間的依賴關(guān)系,并重新編譯需要更新的文件。目標(biāo)clean并不是一個文 件,而是一個動作名,如果你不想使用clean,那么它和其他的規(guī)則模塊沒有任何 關(guān)系。 3.make如何處理makefile文件: make一般從第一個規(guī)則塊(rule)開始(以.開頭的目標(biāo)名不能算作一個 rule),被稱作默認(rèn)目標(biāo)(default goal),也就是make命令要生成的最終 文件。如上例,edit是最終的目標(biāo)文件,被作為第一個rule。當(dāng)你發(fā)出make命令 后,make命令查找當(dāng)前目錄中的makefile文件,然后開始執(zhí)行 第一個rule。如上例,第一個rule就是生成edit可執(zhí)行文件。在完全執(zhí)行 該rule之前,它先要處理該rule中所有的依賴(dependencies)。而這些依賴 (dependencies)又必須根據(jù)它們自己的rule來生成。如果一個目標(biāo)文件的依 賴文件比它本身更新,或者目標(biāo)文件根本就不存在,那么將根據(jù)對應(yīng)的rule 重新編譯生成新目標(biāo)文件。除了第一個rule外,其它的rule也能執(zhí)行,是因 為第一個rule的依賴(dependencies)與其他的rule有關(guān),否則只有第一個 rule被執(zhí)行;如果你想執(zhí)行出第一個rule以外的其他獨立rule,那么就必須 通過make命令行參數(shù)來指明,例如上面的make clean。 4.makefile文件中變量的使用: 例如,我們常常用objects, OBJECTS, objs, OBJS, obj, 或者OBJ, 來 表示目標(biāo)文件,例如上例,我們可以用: objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o 那么在makefile文件中,可用$(objects)代替上述八個.o文件。 5.讓make命令自己推理: make命令有一個隱含的規(guī)則,它能通過查找同名的.c文件和cc -c命令來 自動更新.o文件。也就是在一個rule中,能自動把.c文件添加到依賴 (dependencies)列表中。這樣上述例子可簡寫為: objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o 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) 6.makefile的另一種風(fēng)格: 把目標(biāo)文件放在一起而不是把依賴放在一起,上例可修改為: objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) $(objects) : defs.h kbd.o command.o files.o : command.h display.o insert.o search.o files.o : buffer.h 但是有人也不喜歡它,因為它不能一次看清某個目標(biāo)文件的依賴情況。 7.刪除目錄或文件的rule: .PHONY : clean clean : -rm edit $(objects) 其中,.PHONY : clean 可阻止make命令使用一個名為clean的真實文件,具體見 以后分析。 8.怎樣編寫一個makefile文件: makefile包含五個方面:explicit rules(顯式rule), implicit rules(隱式 rule), variable definitions(變量), directives(指示符), 和comments(注釋) 。顯式rule,指明目標(biāo)文件的依賴以及創(chuàng)建或更新目標(biāo)文件所用的命令;隱式 rule通過同名文件和指定命令來創(chuàng)建和更新目標(biāo)文件;變量的定義見上面的例子 ;指示符是為了幫助make命令在讀取makefile文件時作一些特定的事情(見以后分 析);注釋行一般用#開頭。 9.命名一個makefile文件: 默認(rèn)情況下,make命令會尋找下列文件:GNUmakefile, makefile和Makefile 。如果你不指定makefile文件,那么你必須指定一個最終的目標(biāo)文件,make命令 會自動使用內(nèi)部隱含的rule來編譯。如果你不想用默認(rèn)的makefile文件名,你也 可以通過 -f filename 或 --file=filename,來告訴make應(yīng)該讀取的文件。如果 你用 -f或 --file指定了多個文件,那么它們將按順序被聯(lián)接在一起。如果你用 -f或 --file指定,那么將不自動查找默認(rèn)的makefile等文件。 10.包含其他的makefile文件: include標(biāo)識符告在訴make命令,在讀makefile文件之前,要先讀若干個其他 的makefile文件。include標(biāo)識符使用方法為:include filenames...。在每行開 頭的空格被忽略。但是不能以tab健開頭,否則可能會被當(dāng)作一個命令行。在 include和filename之間必須要用空格隔開。當(dāng)make處理一個include標(biāo)識符時, 它先暫緩處理當(dāng)前的makefile,轉(zhuǎn)而讀該標(biāo)識符所列舉的文件。當(dāng)這些文件被處 理完畢后,make接著讀被懸掛的makefile文件。 11.假冒的目標(biāo)(phony target): 一個假冒目標(biāo)不是一個真正的文件名,它僅僅表示某些特定make命令的擴(kuò)展 ,用假冒的目標(biāo)文件有兩個原因:避免和同名文件發(fā)生沖突。例如: clean: rm *.o temp 因為rm命令不能創(chuàng)建一個clean文件,可能永遠(yuǎn)都沒有那樣的文件存在。因此,每 當(dāng)你執(zhí)行make clean命令時,rm命令都會被執(zhí)行。但是如果有一個clean文件存在 了,那么這個假冒的目標(biāo)將不會工作。因為它沒有依賴,所以所存在的clean文件 被認(rèn)為是最新的,而導(dǎo)致rm命令不能被執(zhí)行。為了避免這個問題,可以顯式申明 該目標(biāo)是phony類型,即: .PHONY: clean clean: rm *.o temp 申明以后,就可以知道clean并非一個真正的文件,在每次執(zhí)行make clean時,它 都必須被執(zhí)行。當(dāng)然,Phony targets也可以有依賴。當(dāng)一個目錄包含幾個程序時 ,在一個makefile文件中描述所有這些程序也很方便。用all假冒目標(biāo)來表示,例 如: all : prog1 prog2 prog3 .PHONY : all prog1 : prog1.o utils.o cc -o prog1 prog1.o utils.o prog2 : prog2.o cc -o prog2 prog2.o prog3 : prog3.o sort.o utils.o cc -o prog3 prog3.o sort.o utils.o 現(xiàn)在只需要用make命令就可以重新編譯這三個文件,也可用參數(shù)來指定編譯特定 的文件,例如make prog1 prog3。 12.主要定義變量: $* 不包含擴(kuò)展名的目標(biāo)文件名稱。 $+ 所有的依賴文件,以空格分開,并以出現(xiàn)的先后為序,可能包含重復(fù)的 依賴文件。 $< 第一個依賴文件的名稱。 $? 所有依賴文件,以空格分開,這些依賴文件的修改日期比目標(biāo)文件的創(chuàng) 建日期晚。 $@ 目標(biāo)的完整名稱。 $^ 所有的依賴文件,以空格分開,不包含重復(fù)的依賴文件。 $% 如果目標(biāo)是歸檔成員,則該變量表示目標(biāo)的歸檔成員名。 13.用戶的標(biāo)準(zhǔn)目標(biāo): 所有的GNU程序都應(yīng)該有些列目標(biāo)(部分略): all: 編譯全部程序。它應(yīng)該是缺省的目標(biāo)。 install: 編譯全部程序,并把可執(zhí)行文件,庫文件等文件拷貝到它應(yīng)該在的 目錄。 clean: 刪除文件。 歡迎訪問FREOS項目主頁 *********************minix的boot目錄下makefile解析******************* # Makefile for the boot monitor package. 注釋 # CC= exec cc 命令 CC86= exec cc -mi86 -Was-ncc CFLAGS= -I.. -m -O LD= $(CC) -s -.o LD86= $(CC86) -.o BIN= /usr/bin MDEC= /usr/mdec all: bootblock boot masterboot extboot installboot edparams 目標(biāo)文件 installboot.o bootimage.o: image.h boot.o bootimage.o: boot.h rawfs.o rawfs86.o installboot.o boot.o bootimage.o: rawfs.h 申明依賴關(guān)系 bootblock: bootblock.s $(LD86) bootblock.s -o bootblock masterboot: masterboot.s $(LD86) masterboot.s -o masterboot extboot: extboot.s $(LD86) extboot.s -o extboot boot.o: boot.c $(CC86) $(CFLAGS) -c boot.c bootimage.o: bootimage.c $(CC86) $(CFLAGS) -c bootimage.c rawfs86.o: rawfs.c rawfs.o ln -f rawfs.c rawfs86.c $(CC86) $(CFLAGS) -c rawfs86.c rm rawfs86.c -cmp -s rawfs.o rawfs86.o && ln -f rawfs.o rawfs86.o boot: boothead.s boot.o bootimage.o rawfs86.o $(LD86) boothead.s -i boot.o bootimage.o rawfs86.o -o boot install -S 12kb boot installboot: installboot.o rawfs.o $(CC) $(STRIP) -i -o installboot installboot.o rawfs.o install -S 6kw installboot edparams: edparams.c $(CC) $(CFLAGS) $(STRIP) -i -o edparams edparams.c install -S 16kw edparams install: $(MDEC)/bootblock $(MDEC)/boot $(MDEC)/masterboot \ $(MDEC)/extboot $(BIN)/installboot $(BIN)/edparams 執(zhí)行make install命令才執(zhí)行? $(MDEC)/bootblock: bootblock install -cs -o bin -m 644 $? $@ $(MDEC)/boot: boot install -cs -o bin -m 644 $? $@ $(MDEC)/masterboot: masterboot install -cs -o bin -m 644 $? $@ $(MDEC)/extboot: extboot install -cs -o bin -m 644 $? $@ $(BIN)/installboot: installboot install -cs -o bin $? $@ $(BIN)/edparams: edparams install -cs -o bin $? $@ clean: rm -f *.bak *.o rm -f bootblock installboot boot masterboot extboot edparams |
|
|