国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

Makefile基礎(chǔ) 4. 自動處理頭文件的依賴關(guān)系

2019-11-08 03:15:30
字體:
供稿:網(wǎng)友

轉(zhuǎn)自:http://blog.csdn.net/weiwangchao_/article/details/18799309

現(xiàn)在我們的Makefile寫成這樣:

all: mainmain: main.o stack.o maze.o	gcc $^ -o $@main.o: main.h stack.h maze.hstack.o: stack.h main.hmaze.o: maze.h main.hclean:	-rm main *.o.PHONY: clean

按照慣例,用all做缺省目標(biāo)?,F(xiàn)在還有一點(diǎn)比較麻煩,在寫main.o、stack.omaze.o這三個目標(biāo)的規(guī)則時要查看源代碼,找出它們依賴于哪些頭文件,這很容易出錯,一是因?yàn)橛械念^文件包含在另一個頭文件中,在寫規(guī)則時很容易遺漏,二是如果以后修改源代碼改變了依賴關(guān)系,很可能忘記修改Makefile的規(guī)則。為了解決這個問題,可以用gcc-M選項(xiàng)自動生成目標(biāo)文件和源文件的依賴關(guān)系:

$ gcc -M main.cmain.o: main.c /usr/include/stdio.h /usr/include/features.h /  /usr/include/sys/cdefs.h /usr/include/bits/Wordsize.h /  /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h /  /usr/lib/gcc/i486-linux-gnu/4.3.2/include/stddef.h /  /usr/include/bits/types.h /usr/include/bits/typesizes.h /  /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h /  /usr/lib/gcc/i486-linux-gnu/4.3.2/include/stdarg.h /  /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h main.h /  stack.h maze.h

-M選項(xiàng)把stdio.h以及它所包含的系統(tǒng)頭文件也找出來了,如果我們不需要輸出系統(tǒng)頭文件的依賴關(guān)系,可以用-MM選項(xiàng):

$ gcc -MM *.cmain.o: main.c main.h stack.h maze.hmaze.o: maze.c maze.h main.hstack.o: stack.c stack.h main.h

接下來的問題是怎么把這些規(guī)則包含到Makefile中,GNU make的官方手冊建議這樣寫:

all: mainmain: main.o stack.o maze.o	gcc $^ -o $@clean:	-rm main *.o.PHONY: cleansources = main.c stack.c maze.cinclude $(sources:.c=.d)%.d: %.c	set -e; rm -f $@; /	$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; /	sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.$$$$ > $@; /	rm -f $@.$$$$

sources變量包含我們要編譯的所有.c文件,$(sources:.c=.d)是一個變量替換語法,把sources變量中每一項(xiàng)的.c替換成.d,所以include這一句相當(dāng)于:

include main.d stack.d maze.d

類似于C語言的#include指示,這里的include表示包含三個文件main.d、stack.dmaze.d,這三個文件也應(yīng)該符合Makefile的語法。如果現(xiàn)在你的工作目錄是干凈的,只有.c文件、.h文件和Makefile,運(yùn)行make的結(jié)果是:

$ makeMakefile:13: main.d: No such file or directoryMakefile:13: stack.d: No such file or directoryMakefile:13: maze.d: No such file or directoryset -e; rm -f maze.d; /	cc -MM  maze.c > maze.d.$$; /	sed 's,/(maze/)/.o[ :]*,/1.o maze.d : ,g' < maze.d.$$ > maze.d; /	rm -f maze.d.$$set -e; rm -f stack.d; /	cc -MM  stack.c > stack.d.$$; /	sed 's,/(stack/)/.o[ :]*,/1.o stack.d : ,g' < stack.d.$$ > stack.d; /	rm -f stack.d.$$set -e; rm -f main.d; /	cc -MM  main.c > main.d.$$; /	sed 's,/(main/)/.o[ :]*,/1.o main.d : ,g' < main.d.$$ > main.d; /	rm -f main.d.$$cc    -c -o main.o main.ccc    -c -o stack.o stack.ccc    -c -o maze.o maze.cgcc main.o stack.o maze.o -o main

一開始找不到.d文件,所以make會報警告。但是make會把include的文件名也當(dāng)作目標(biāo)來嘗試更新,而這些目標(biāo)適用模式規(guī)則%.d: %c,所以執(zhí)行它的命令列表,比如生成maze.d的命令:

set -e; rm -f maze.d; /	cc -MM  maze.c > maze.d.$$; /	sed 's,/(maze/)/.o[ :]*,/1.o maze.d : ,g' < maze.d.$$ > maze.d; /	rm -f maze.d.$$

注意,雖然在Makefile中這個命令寫了四行,但其實(shí)是一條命令,make只創(chuàng)建一個Shell進(jìn)程執(zhí)行這條命令,這條命令分為5個子命令,用;號隔開,并且為了美觀,用續(xù)行符/拆成四行來寫。執(zhí)行步驟為:

set -e命令設(shè)置當(dāng)前Shell進(jìn)程為這樣的狀態(tài):如果它執(zhí)行的任何一條命令的退出狀態(tài)非零則立刻終止,不再執(zhí)行后續(xù)命令。

把原來的maze.d刪掉。

重新生成maze.c的依賴關(guān)系,保存成文件maze.d.1234(假設(shè)當(dāng)前Shell進(jìn)程的id是1234)。注意,在Makefile中$有特殊含義,如果要表示它的字面意思則需要寫兩個$,所以Makefile中的四個$傳給Shell變成兩個$,兩個$在Shell中表示當(dāng)前進(jìn)程的id,一般用它給臨時文件起名,以保證文件名唯一。

這個sed命令比較復(fù)雜,就不細(xì)講了,主要作用是查找替換。maze.d.1234的內(nèi)容應(yīng)該是maze.o: maze.c maze.h main.h,經(jīng)過sed處理之后存為maze.d,其內(nèi)容是maze.o maze.d: maze.c maze.h main.h。

最后把臨時文件maze.d.1234刪掉。

不管是Makefile本身還是被它包含的文件,只要有一個文件在make過程中被更新了,make就會重新讀取整個Makefile以及被它包含的所有文件,現(xiàn)在main.dstack.dmaze.d都生成了,就可以正常包含進(jìn)來了(假如這時還沒有生成,make就要報錯而不是報警告了),相當(dāng)于在Makefile中添了三條規(guī)則:

main.o main.d: main.c main.h stack.h maze.hmaze.o maze.d: maze.c maze.h main.hstack.o stack.d: stack.c stack.h main.h

如果我在main.c中加了一行#include "foo.h",那么:

1、main.c的修改日期變了,根據(jù)規(guī)則main.o main.d: main.c main.h stack.h maze.h要重新生成main.omain.d。生成main.o的規(guī)則有兩條:

main.o: main.c main.h stack.h maze.h%.o: %.c#  commands to execute (built-in):        $(COMPILE.c) $(OUTPUT_OPTION) $<

第一條是把規(guī)則main.o main.d: main.c main.h stack.h maze.h拆開寫得到的,第二條是隱含規(guī)則,因此執(zhí)行cc命令重新編譯main.o。生成main.d的規(guī)則也有兩條:

main.d: main.c main.h stack.h maze.h%.d: %.c	set -e; rm -f $@; /	$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; /	sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.$$$$ > $@; /	rm -f $@.$$$$

因此main.d的內(nèi)容被更新為main.o main.d: main.c main.h stack.h maze.h foo.h。

2、由于main.d被Makefile包含,main.d被更新又導(dǎo)致make重新讀取整個Makefile,把新的main.d包含進(jìn)來,于是新的依賴關(guān)系生效了。

sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.$$$$ > $@; /解釋:/1是對/($*/)的引用,將多個空格和冒號合并成一個冒號


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 共和县| 浮梁县| 西乡县| 青岛市| 信宜市| 仙居县| 长春市| 滨州市| 金乡县| 谷城县| 灌云县| 乌兰察布市| 青阳县| 门源| 洛阳市| 六盘水市| 五台县| 剑河县| 山西省| 诏安县| 偏关县| 福泉市| 遂川县| 沛县| 皮山县| 德保县| 萝北县| 昔阳县| 浦县| 莱阳市| 乐都县| 炉霍县| 通州市| 东兰县| 长岭县| 修武县| 汤阴县| 张家口市| 康乐县| 吉首市| 晴隆县|