在上一篇 《【Linux + Makefile】十分鐘教你學(xué)會(huì)Makefile的FORCE》文章的最后,筆者就FORCE的用法在一個(gè)示例工程中使用,提出了一個(gè)問題:為何build_info.h每次都是新生成的(有修改過),而main.c又是有include “build-info.h”,但main.c卻不是每次都重新編譯呢?這個(gè)到底是不是違反了Makefile的基本規(guī)則呢?本文將給你答案,通過閱讀本文,你將了解到以下內(nèi)容:
- 如何保證在C文件中包含的頭文件修改了的時(shí)候,C文件每次都會(huì)被重新編譯?
為了更好地展示上訴描述的問題,我們將之前的示例工程稍微復(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ì)重新生成,按照我們之前的寫法,我們Makefile可能就是這樣:
SHELL = /bin/bash #指定shell使用/bin/bash,否則echo -e可能會(huì)出問題
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
執(zhí)行make,我們會(huì)發(fā)現(xiàn),跟我們的預(yù)期不一樣:它雖然會(huì)每次都生成build_info.h,但是main.c包含了build_info.h卻不會(huì)每次都重新編譯。這個(gè)問題發(fā)生的原因,我們來分析下:
在我們的Makefile規(guī)則中,main.o只依賴于main.c (Makefile 第18-19行),而在第二次執(zhí)行make的時(shí)候,main.c顯然并沒有被修改,所以main.o不會(huì)重新生成,自然可執(zhí)行文件就不會(huì)重新生成。這里的問題根源在于,main.c它是依賴于build_info.h的,而這個(gè)依賴關(guān)系并沒有體現(xiàn)在Makefile中,所以整個(gè)編譯流程達(dá)不到我們的預(yù)期想法。我們嘗試下,將main.c的依賴頭文件也寫入到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ì)出問題
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é)果如下所示:
再次執(zhí)行make,多試幾次,一樣的結(jié)果。
由上可知,經(jīng)過改造后的Makefile是實(shí)現(xiàn)了我們的需求,每次build_info.h重新生成,導(dǎo)致main.c包含了build_info.h也會(huì)重新編譯,而a.c和b.c沒有被修改,所以在未執(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有疑問,歡迎在評(píng)論席提出你的疑問,博主很樂意為你解答。
延伸閱讀:
【Linux + Makefile】十分鐘教你學(xué)會(huì)Makefile的FORCE
?審核編輯:湯梓紅
-
Linux
+關(guān)注
關(guān)注
87文章
11320瀏覽量
209832 -
Makefile
+關(guān)注
關(guān)注
1文章
125瀏覽量
19191 -
C文件
+關(guān)注
關(guān)注
0文章
12瀏覽量
2857
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論