在上一篇 《【Linux + Makefile】十分鐘教你學(xué)會(huì)Makefile的FORCE》文章的最后,筆者就FORCE的用法在一個(gè)示例工程中使用,提出了一個(gè)問(wèn)題:為何build_info.h每次都是新生成的(有修改過(guò)),而main.c又是有include “build-info.h”,但main.c卻不是每次都重新編譯呢?這個(gè)到底是不是違反了Makefile的基本規(guī)則呢?本文將給你答案,通過(guò)閱讀本文,你將了解到以下內(nèi)容:
- 如何保證在C文件中包含的頭文件修改了的時(shí)候,C文件每次都會(huì)被重新編譯?
為了更好地展示上訴描述的問(wèn)題,我們將之前的示例工程稍微復(fù)雜化一點(diǎn)點(diǎn):
整個(gè)工程有3個(gè).c文件,a.c/b.c/main.c,其中main.c會(huì)調(diào)用a.c/b.c中的兩個(gè)接口,同時(shí)main.c會(huì)include頭文件build_info.h;這個(gè)build_info.h每次編譯都會(huì)重新生成,按照我們之前的寫(xiě)法,我們Makefile可能就是這樣:
SHELL = /bin/bash #指定shell使用/bin/bash,否則echo -e可能會(huì)出問(wèn)題
ECHO = echo
BIN = test
BUILG_INFO_H = build_info.h
SRC-C-y += a.c
SRC-C-y += b.c
SRC-C-y += main.c
SRC-O = $(patsubst %.c, $(O)%.o, $(SRC-C-y))
all: gen_build_info $(BIN)
clean:
rm -rf $(SRC-O) $(BIN) $(BUILG_INFO_H)
$(BIN) : $(SRC-O)
gcc -o $(O)"$@" $(SRC-O)
%.o : %.c
gcc -c "$<" -o "$@"
gen_build_info: $(BUILG_INFO_H)
$(BUILG_INFO_H): FORCE #強(qiáng)制生成build_info.h
@$(RM) $@
@$(ECHO) ' GEN $@'
@$(ECHO) -e " #ifndef __BUILD_INFO_H__\n"\
"#define __BUILD_INFO_H__\n"\
"#define APP_TIME \"`date "+%Y-%m-%d %H:%M:%S"`\"\n"\
"#endif" > $@
FORCE:
.PHONY: FORCE
![poYBAGDYdXCAWkKMAAAAK8RNs4s030.png](https://file.elecfans.com/web2/M00/03/FB/poYBAGDYdXCAWkKMAAAAK8RNs4s030.png)
執(zhí)行make,我們會(huì)發(fā)現(xiàn),跟我們的預(yù)期不一樣:它雖然會(huì)每次都生成build_info.h,但是main.c包含了build_info.h卻不會(huì)每次都重新編譯。這個(gè)問(wèn)題發(fā)生的原因,我們來(lái)分析下:
在我們的Makefile規(guī)則中,main.o只依賴于main.c (Makefile 第18-19行),而在第二次執(zhí)行make的時(shí)候,main.c顯然并沒(méi)有被修改,所以main.o不會(huì)重新生成,自然可執(zhí)行文件就不會(huì)重新生成。這里的問(wèn)題根源在于,main.c它是依賴于build_info.h的,而這個(gè)依賴關(guān)系并沒(méi)有體現(xiàn)在Makefile中,所以整個(gè)編譯流程達(dá)不到我們的預(yù)期想法。我們嘗試下,將main.c的依賴頭文件也寫(xiě)入到Makefile中,怎么實(shí)現(xiàn)呢?
恰好,GCC給了我們強(qiáng)大的支持,它有個(gè)非常有用的選項(xiàng) -MD -MF,它可以在生成一個(gè).o的同時(shí)也生成它的依賴文件列表,修改后的Makefile如下所示:
SHELL = /bin/bash #指定shell使用/bin/bash,否則echo -e可能會(huì)出問(wèn)題
ECHO = echo
BIN = test
BUILG_INFO_H = build_info.h
SRC-C-y += a.c
SRC-C-y += b.c
SRC-C-y += main.c
SRC-O = $(patsubst %.c, $(O)%.o, $(SRC-C-y))
SRC-C-DEPS = $(patsubst %.c, $(O).%.o.d, $(SRC-C-y)) ## 由 a.c ==> .a.o.d
all: gen_build_info $(BIN)
clean:
rm -rf $(SRC-O) $(BIN) $(BUILG_INFO_H) $(SRC-C-DEPS)
$(BIN) : $(SRC-O)
gcc -o $(O)"$@" $(SRC-O)
%.o : %.c
# 生成xxx.o的時(shí)候,同時(shí)生成它的依賴列表,放在文件.xxx.o.d中
gcc -c "$<" -o "$@" -MD -MF "$(dir $@).$(notdir $@).d" -MT "$@"
gen_build_info: $(BUILG_INFO_H)
$(BUILG_INFO_H): FORCE #強(qiáng)制生成build_info.h
@$(RM) $@
@$(ECHO) ' GEN $@'
@$(ECHO) -e " #ifndef __BUILD_INFO_H__\n"\
"#define __BUILD_INFO_H__\n"\
"#define APP_TIME \"`date "+%Y-%m-%d %H:%M:%S"`\"\n"\
"#endif" > $@
FORCE:
.PHONY: FORCE
# 在Makefile末尾強(qiáng)制包含這些依賴文件
-include $(SRC-C-DEPS)
測(cè)試結(jié)果如下所示:
![](https://file.elecfans.com//web2/M00/67/86/poYBAGMYfYaAOHsMAADL-vOLPSc169.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N6dWxsYw==,size_16,color_FFFFFF,t_70)
再次執(zhí)行make,多試幾次,一樣的結(jié)果。
![](https://file.elecfans.com//web2/M00/68/1F/pYYBAGMYfYaARBtFAADJ2a17VUs636.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N6dWxsYw==,size_16,color_FFFFFF,t_70)
由上可知,經(jīng)過(guò)改造后的Makefile是實(shí)現(xiàn)了我們的需求,每次build_info.h重新生成,導(dǎo)致main.c包含了build_info.h也會(huì)重新編譯,而a.c和b.c沒(méi)有被修改,所以在未執(zhí)行make clean的情況下,a.c和b.c是不會(huì)被重新編譯的,每次都是僅僅main.c被再次編譯,從而重新生成新的test可執(zhí)行文件。這樣就是已經(jīng)達(dá)到了【當(dāng)C文件包含的頭文件修改了的時(shí)候,C文件必須重新編譯】的目的。
以上就是關(guān)于Makefile的高階用法,基本滿足了我們?nèi)粘9こ虒?shí)踐的需求。如果你對(duì)該Makefile有疑問(wèn),歡迎在評(píng)論席提出你的疑問(wèn),博主很樂(lè)意為你解答。
延伸閱讀:
【Linux + Makefile】十分鐘教你學(xué)會(huì)Makefile的FORCE
?審核編輯:湯梓紅
-
Linux
+關(guān)注
關(guān)注
87文章
11345瀏覽量
210398 -
Makefile
+關(guān)注
關(guān)注
1文章
125瀏覽量
19219 -
C文件
+關(guān)注
關(guān)注
0文章
12瀏覽量
2870
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
C語(yǔ)言中的頭文件能不能重復(fù)包含
Keil工程下改動(dòng).c文件后編譯的.o文件不更新如何解決?
linux驅(qū)動(dòng)程序的編譯方法有哪兩種
可重復(fù)頭文件的固定結(jié)構(gòu)
![可重復(fù)<b class='flag-5'>頭文件</b>的固定結(jié)構(gòu)](https://file1.elecfans.com/web2/M00/04/89/wKgZombP27mAdF_oABgD4t0KO4M564.png)
如何修改buildroot和debian文件系統(tǒng)
![如何<b class='flag-5'>修改</b>buildroot和debian<b class='flag-5'>文件</b>系統(tǒng)](https://file1.elecfans.com/web2/M00/FD/B9/wKgZomaeKpCAeS1mAAJr5bnMFl8719.png)
SDK 1.0移植到eclipse失敗,如何修改makefile文件呢?
IDF-V4.3環(huán)境下包含了庫(kù)的頭文件會(huì)編譯報(bào)錯(cuò),為什么?
components包含頭文件錯(cuò)誤是怎么回事?
快來(lái)用Makefile管理工程,提高工作效率!
![快來(lái)用<b class='flag-5'>Makefile</b>管理工程,提高工作效率!](https://file.elecfans.com/web2/M00/20/B3/pYYBAGGfNNmAK-PZAAJsGM5Cgk0227.jpg)
請(qǐng)問(wèn)頭文件能不能定義變量呢?
HighTec Tricore編譯速度優(yōu)化策略探討
![HighTec Tricore<b class='flag-5'>編譯</b>速度優(yōu)化策略探討](https://file1.elecfans.com/web2/M00/C8/A0/wKgaomYWGV2AYPo0AAAPok0cS84452.png)
評(píng)論