7 makefile文件的條件語句
一個條件語句可以導致根據變量的值執行或忽略makefile文件中一部分腳本。條件語句可以將一個變量與其它變量的值相比較,或將一個變量與一字符串常量相比較。條件語句用於控制make實際看見的makefile文件部分,不能用於在執行時控制shell命令。
7.1條件語句的例子
下述的條件語句的例子告訴make如果變量CC的值是‘gcc’時使用一個數據庫,如不是則使用其它數據庫。它通過控制選擇兩命令行之一作為該規則的命令來工作。‘CC=gcc’作為make改變的參數的結果不僅用於決定使用哪一個編譯器,而且決定連接哪一個數據庫。
libs_for_gcc = -lgnu
normal_libs =
foo: $(objects)
ifeq ($(CC),gcc)
$(CC) -o foo $(objects) $(libs_for_gcc)
else
$(CC) -o foo $(objects) $(normal_libs)
endif
該條件語句使用三個指令:ifeq、else和endif。
Ifeq指令是條件語句的開始,並指明條件。它包含兩個參數,它們被逗號分開,並被擴在圓括號內。運行時首先對兩個參數變量替換,然后進行比較。在makefile中跟在ifeq后面的行是符合條件時執行的命令;否則,它們將被忽略。
如果前面的條件失敗,else指令將導致跟在其后面的命令執行。在上述例子中,意味着當第一個選項不執行時,和第二個選項連在一起的命令將執行。在條件語句中,else指令是可選擇使用的。
Endif指令結束條件語句。任何條件語句必須以endif指令結束,后跟makefile文件中的正常內容。
上例表明條件語句工作在原文水平:條件語句的行根據條件要么被處理成makefile文件的一部分或要么被忽略。這是makefile文件重大的語法單位(例如規則)可以跨越條件語句的開始或結束的原因。
當變量CC的值是gcc,上例的效果為:
foo: $(objects)
$(CC) -o foo $(objects) $(libs_for_gcc)
當變量CC的值不是gcc而是其它值的時候,上例的效果為:
foo: $(objects)
$(CC) -o foo $(objects) $(normal_libs)
相同的結果也能使用另一種方法獲得:先將變量的賦值條件化,然后再使用變量:
libs_for_gcc = -lgnu
normal_libs =
ifeq ($(CC),gcc)
libs=$(libs_for_gcc)
else
libs=$(normal_libs)
endif
foo: $(objects)
$(CC) -o foo $(objects) $(libs)
7.2條件語句的語法
對於沒有else指令的條件語句的語法為:
conditional-directive
text-if-true
endif
‘text-if-true’可以是任何文本行,在條件為‘真’時它被認為是makefile文件的一部分;如果條件為‘假’,將被忽略。完整的條件語句的語法為:
conditional-directive
text-if-true
else
text-if-false
endif
如果條件為‘真’,使用‘text-if-true’;如果條件為‘假’,使用‘text-if-false’。‘text-if-false’可以是任意多行的文本。
關於‘conditional-directive’的語法對於簡單條件語句和復雜條件語句完全一樣。有四種不同的指令用於測試不同的條件。下面是指令表:
ifeq (arg1, arg2)
ifeq 'arg1' 'arg2'
ifeq "arg1" "arg2"
ifeq "arg1" 'arg2'
ifeq 'arg1' "arg2"
擴展參數arg1、arg2中的所有變量引用,並且比較它們。如果它們完全一致,則使用‘text-if-true’,否則使用‘text-if-false’(如果存在的話)。您經常要測試一個變量是否有非空值,當經過復雜的變量和函數擴展得到一個值,對於您認為是空值,實際上有可能由於包含空格而被認為不是空值,由此可能造成混亂。對於此,您可以使用strip函數從而避免空格作為非空值的干擾。例如:
ifeq ($(strip $(foo)),)
text-if-empty
endif
即使$(foo)中含有空格,也使用‘text-if-empty’。
ifneq (arg1, arg2)
ifneq 'arg1' 'arg2'
ifneq "arg1" "arg2"
ifneq "arg1" 'arg2'
ifneq 'arg1' "arg2"
擴展參數arg1、arg2中的所有變量引用,並且比較它們。如果它們不同,則使用‘text-if-true’,否則使用‘text-if-false’(如果存在的話)。
ifdef variable-name
如果變量‘variable-name’是非空值,‘text-if-true’有效,否則,‘text-if-false’有效(如果存在的話)。變量從沒有被定義過則變量是空值。注意ifdef僅僅測試變量是否有值。它不能擴展到看變量是否有非空值。因而,使用ifdef測試所有定義過的變量都返回‘真’,但那些象‘foo=’情況除外。測試空值請使用ifeq($(foo),)。例如:
bar =
foo = $(bar)
ifdef foo
frobozz = yes
else
frobozz = no
endif
設置‘frobozz'的值為‘yes', 而::
foo =
ifdef foo
frobozz = yes
else
frobozz = no
endif
設置‘frobozz' 為‘no'。
ifndef variable-name
如果變量‘variable-name’是空值,‘text-if-true’有效,否則,‘text-if-false’有效(如果存在的話)。
在指令行前面允許有多余的空格,它們在處理時被忽略,但是不允許有Tab(如果一行以Tab開始,那么該行將被認為是規則的命令行)。除此之外,空格和Tab可以插入到行的任何地方,當然指令名和參數中間除外。以‘#’開始的注釋可以在行的結尾。
在條件語句中另兩個有影響的指令是else和endif。這兩個指令以一個單詞的形式出現,沒有任何參數。在指令行前面允許有多余的空格,空格和Tab可以插入到行的中間,以‘#’開始的注釋可以在行的結尾。
條件語句影響make使用的makefile文件。如果條件為‘真’,make讀入‘text-if-true’包含的行;如果條件為‘假’,make讀入‘text-if-false’包含的行(如果存在的話);makefile文件的語法單位,例如規則,可以跨越條件語句的開始或結束。
當讀入makefile文件時,Make計算條件的值。因而您不能在測試條件時使用自動變量,因為他們是命令執行時才被定義(參閱自動變量)。
為了避免不可忍受的混亂,在一個makefile文件中開始一個條件語句,而在另外一個makefile文件中結束這種情況是不允許的。然而如果您試圖引入包含的makefile文件不中斷條件語句,您可以在條件語句中編寫include指令。
7.3測試標志的條件語句
您可以使用變量MAKEFLAGS和findstring函數編寫一個條件語句,用它來測試例如‘-t’等的make命令標志(參閱字符串替換和分析的函數)。這適用於僅使用touch標志不能完全更改文件的時間戳的場合。
findstring函數檢查一個字符串是否為另一個字符串的子字符串。如果您要測試‘-t’標志,使用‘-t’作為第一個字符串,將變量MAKEFLAGS的值作為另一個字符串。例如下面的例子是安排使用‘ranlib –t’完成一個檔案文件的更新:
archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
+touch archive.a
+ranlib -t archive.a
else
ranlib archive.a
endif
前綴‘+’表示這些命令行是遞歸調用行,即使是用‘-t’標志它們一樣要執行。參閱遞歸調用make
