C語言的本質(37)——makefile之隱含規則和模式規則
Makefile有很多靈活的寫法,可以寫得更簡潔,同時減少出錯的可能。本節我們來看看這樣一個例子還有哪些改進的餘地。
一個目標依賴的所有條件不一定非得寫在一條規則中,也可以拆開寫,例如:
main.o: main.h stack.h maze.h
main.o: main.c
gcc-c main.c
就相當於:
main.o: main.c main.h stack.h maze.h
gcc-c main.c
如果一個目標拆開寫多條規則,其中只有一條規則允許有命令列表,其它規則應該沒有命令列表,否則make會報警告並且採用最後一條規則的命令列表。
這樣我們的例子可以改寫成:
main: main.o stack.o maze.o
gccmain.o stack.o maze.o -o main
main.o: main.h stack.h maze.h
stack.o: stack.h main.h
maze.o: maze.h main.h
main.o: main.c
gcc-c main.c
stack.o: stack.c
gcc-c stack.c
maze.o: maze.c
gcc-c maze.c
clean:
-rmmain *.o
.PHONY: clean
這不是比原來更繁瑣了嗎?現在可以把提出來的三條規則刪去,寫成:
main: main.o stack.o maze.o
gccmain.o stack.o maze.o -o main
main.o: main.h stack.h maze.h
stack.o: stack.h main.h
maze.o: maze.h main.h
clean:
-rmmain *.o
.PHONY: clean
這就比原來簡單多了。可是現在main.o、stack.o和maze.o這三個目標連編譯命令都沒有了,怎麼編譯的呢?試試看:
$ make
cc -c -o main.o main.c
cc -c -o stack.o stack.c
cc -c -o maze.o maze.c
gcc main.o stack.o maze.o -o main
現在解釋一下前三條編譯命令是怎麼來。如果一個目標在Makefile中的所有規則都沒有命令列表,make會嘗試在內建的隱含規則(Implicit Rule)資料庫中查詢適用的規則。make的隱含規則資料庫可以用make -p命令列印,列印出來的格式也是Makefile的格式,包括很多變數和規則,其中和我們這個例子有關的隱含規則有:
# default
OUTPUT_OPTION = -o $@
# default
CC = cc
# default
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS)$(TARGET_ARCH) -c
%.o: %.c
# commands to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
#號在Makefile中表示單行註釋,就像C語言的//註釋一樣。CC是一個Makefile變數,用CC = cc定義和賦值,用$(CC)取它的值,其值應該是cc。Makefile變數像C的巨集定義一樣,代表一串字元,在取值的地方展開。cc是一個符號連結,通常指向gcc,在有些UNIX系統上可能指向另外一種C編譯器。
CFLAGS這個變數沒有定義,$(CFLAGS)展開是空,CPPFLAGS和TARGET_ARCH也是如此。這樣$(COMPILE.c)展開應該是cc 空 空 空 -c,去掉“空”得到cc -c,注意中間留下4個空格,所以%.o:%.c規則的命令$(COMPILE.c) $(OUTPUT_OPTION) $<展開之後是cc -c -o $@$<,和上面的編譯命令已經很接近了。
$@和$<是兩個特殊的變數,$@的取值為規則中的目標,$<的取值為規則中的第一個條件。%.o: %.c是一種特殊的規則,稱為模式規則(Pattern Rule)。現在回顧一下整個過程,在我們的Makefile中以main.o為目標的規則都沒有命令列表,所以make會查詢隱含規則,發現隱含規則中有這樣一條模式規則適用,main.o符合%.o的模式,現在%就代表main(稱為main.o這個名字的Stem),再替換到%.c中就是main.c。所以這條模式規則相當於:
main.o: main.c
cc -c -o main.o main.c
隨後,在處理stack.o目標時又用到這條模式規則,這時又相當於:
stack.o: stack.c
cc -c -o stack.o stack.c
maze.o也同樣處理。這三條規則可以由make的隱含規則推匯出來,所以不必寫在Makefile中。
先前我們寫Makefile都是以目標為中心,一個目標依賴於若干條件,現在換個角度,以條件為中心,Makefile還可以這麼寫:
main: main.o stack.o maze.o
gccmain.o stack.o maze.o -o main
main.o stack.o maze.o: main.h
main.o maze.o: maze.h
main.o stack.o: stack.h
clean:
-rmmain *.o
.PHONY: clean
我們知道,寫規則的目的是讓make建立依賴關係圖,不管怎麼寫,只要把所有的依賴關係都描述清楚了就行。對於多目標的規則,make會拆成幾條單目標的規則來處理,例如
target1 target2: prerequisite1prerequisite2
command$< -o $@
這樣一條規則相當於:
target1: prerequisite1 prerequisite2
commandprerequisite1 -o target1
target2: prerequisite1 prerequisite2
commandprerequisite1 -o target2
注意兩條規則的命令列表是一樣的,但$@的取值不同。
相關文章
- Makefile基本規則和原理
- C語言的本質(38)——makefile之變數C語言變數
- 【ASM C/C++】 Makefile 規則說明ASMC++
- C語言的本質(36)——makefile基礎C語言
- Drools 規則語言詳解
- 理解C語言宣告的優先順序規則C語言
- make的模式規則模式
- 【java規則引擎】之規則引擎解釋Java
- if測試和語法規則
- C語言學習四 — 函式與作用域規則C語言函式
- 規則引擎模式 - upperdine模式
- 管理規則和基於規則的轉換——流
- Sass 語法規則
- 【java規則引擎】規則引擎RuleBase中利用觀察者模式Java模式
- Perl語法的基本規則
- 從開源專案學習 C 語言基本的編碼規則
- Uniswap質押挖礦系統開發模式規則模式
- JSON語法規則JSON
- JSON 語法規則JSON
- XML 語法規則概述XML
- CSS @page語法規則CSS
- JAVA語法規則 (轉)Java
- 筆記:隱式轉換規則筆記
- C語言的本質(32)——C語言與彙編之C語言內聯彙編C語言
- 使用DBV的命令規則和規則集強化資料庫安全資料庫
- oracle資料隱式轉換規則Oracle
- jsx基本語法規則JS
- IPP Swap質押挖礦系統開發規則/python技術語言Python
- C# sizeof 計算規則C#
- 正則匹配規則2
- 識別符號的命名規則和規範符號
- Objective-C 記憶體管理之ARC規則Object記憶體
- IT職場規則
- url規則
- jQuery Validate驗證規則實質jQuery
- 尋找適合編寫靜態分析規則的語言
- Performanced C++ 經驗規則(5):再談過載、覆蓋和隱藏ORMC++
- sql語句的一些規則SQL