Makefile中的tab縮進

Makefile中的Tab縮進

這學期選了OOP課,寫了條筆記。

makefile中的縮進的問題,要從makefile的基本結構說起:

target: prerequisite
	recipe (shell commands)

注意這個縮進是個tab,而且只能是tab,不能是空格。在makefile中,tab和空格是嚴格區分開的。每一句recipe(就是要執行的shell命令)的開頭,都必須有一個tab。而makefile中的其他東西,例如target: prerequisiteifeq、變量賦值等等,前面一般不能有tab。也就是說,開頭有沒有tab是區分“makefile中的shell命令(recipe)”和“makefile中的其他語句”的標誌。二者作用不同、語法不同,可以說是兩套系統,大家一定要嚴格區分開。

例1:變量

例如,makefile中的變量和shell中的變量,是兩種不同的東西。舉個例子:

VAR=foo
all:
	VAR=bar; echo $$VAR; echo $(VAR)
# 這裏分號的作用:在同一行寫多條shell命令

這個makefile運行後,輸出的是:

VAR=bar; echo $VAR; echo foo
bar
foo

讓我們逐條分辨一下這個makefile中每一個變量“VAR”的身份。

語句 功能
VAR=foo 定義一個makefile變量"VAR",賦值爲"foo"
VAR=bar 執行shell命令VAR=bar,即:定義一個shell變量"VAR",賦值爲"bar"
echo $$VAR 執行shell命令echo $VAR(makefile中打兩個$是爲了轉義,
相當於在shell中打了一個$),即:輸出shell變量"VAR"的值
echo $(VAR) 將$(VAR)替換成makefile變量"VAR"的值後,執行shell命令,
即:執行shell命令echo foo

請關注VAR=foo一句和VAR=bar一句的區別:正是前面有無tab的區別,導致前者是makefile變量操作,而後者是規則(rule)all: ...中的一條recipe。

例2:ifeq

另外需要注意的是,在ifeq之類的控制語句的語句體中,是不需要額外縮進的。ifeq的作用範圍,由endif的位置決定;而決定是否縮進的,只有recipe和非recipe的區別。舉個極端的例子:

all:
	echo $(VAR)

FLAG=TRUE
VAR=foo

ifeq (TRUE, $(FLAG))
	VAR=bar
endif

上面這個makefile中,如果倒數第二行想要操作makefile中的VAR變量的話,用tab縮進是不對的,應該直接頂格寫,或者打若干空格也行(只要沒有tab,效果就和沒縮進一樣)。

但是,如果對上面這個“錯誤”的代碼運行make,依然會輸出和頂格寫相同的結果:

echo bar
bar

也就是說,儘管倒數第二行的開頭有tab,VAR=bar仍然被識別成makefile變量操作,而不是shell命令——這是因爲它的位置比較特殊,不屬於任何規則,所以沒被識別成shell命令。

但是,一旦我們在ifeq前面插入一條規則:

all:
	echo $(VAR)

FLAG=TRUE
VAR=foo

dummy:

ifeq (TRUE, $(FLAG))
	VAR=bar
endif

再運行make,輸出就會變成:

echo foo
foo

這是因爲VAR=bar一句這次被識別成dummy: ...這條規則中的一條recipe了。爲了驗證,可以運行make dummy試試,果然輸出了VAR=bar,這意味着VAR=bar一句確實被當做shell命令執行了。

爲了避免這樣令人迷惑的事情,我們寫makefile的時候,還是不要在非recipe語句的前面加tab了,直接寫成:

all:
	echo $(VAR)

FLAG=TRUE
VAR=foo

dummy:

ifeq (TRUE, $(FLAG))
VAR=bar
endif

就可以保證無論有無dummy:一行,輸出結果都是:

echo bar
bar
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章