条件语句(六)

来源:互联网 发布:全球经济指标数据网 编辑:程序博客网 时间:2024/05/22 05:20

7 Makefiles的条件语句

条件指令使make可以根据变量的值决定makefile中那些部分会被执行,那些部分会被忽略。条件指令可以比较两个变量的值,也可比较变量和一个常量字符串的值。条件指令决定了make实际看到的makefile内容,因此不可以在执行recipe时使用条件语句。

7.1 条件指令示例

下面的示例中,条件语句告诉make,如果变量CC的值是gcc,则使用一个库文件集,否则使用另一个库文件集。这个条件语句决定了两条recipes中的哪条将被执行。把CC=gcc作为make的参数,将会决定makefile中使用的编译器,以及链接的库文件。

libs_for_gcc = -lgnunormal_libs =foo: $(objects)ifeq ($(CC),gcc)        $(CC) -o foo $(objects) $(libs_for_gcc)else        $(CC) -o foo $(objects) $(nermal_libs)endif

这里条件语句使用了三条指令:ifeqelseendif

ifeq指令开始条件语句,并且指定了条件。其包含两个参数,逗号分隔,并用圆括号括起来。两个参数执行变量替换,然后进行比较。ifeq下面的语句在两个参数匹配时被保留,否则被忽略。

else指令后面的行在条件判断失败时被保留。这个例子中,else表示在不使用第一条链接指令时,使用其后的第二条链接指令。条件指令中的else是一个选项。

endif指令结束条件语句。每个条件指令必须以endif结束。

就像例子中所展示了,条件指令在文本层执行:条件语句中的行根据条件成为makefile的一部分,或者被忽略。这也是为什么makefile中的大型句法单元(如规则)可以横跨条件语句的开始或结束。

当变量CC的值为gcc时,上面的例子中的规则实际成为:

foo: $(objects)        $(CC) -o foo $(objects) $(libs_for_gcc)

当变量CC的值是其它值时,上面的规则变为:

foo: $(objects)        $(CC) -o foo $(objects) $(normal_libs)

上面的结果等效于条件化一个赋值语句,然后在执行规则时使用这个被赋值的变量:

libs_for_gcc = -lgnunormal_libs =ifeq ($(CC),gcc)    libs=$(libs_for_gcc)else    libs=$(normal_libs)endiffoo: $(objects)        $(CC) -o foo $(objects) $(libs)

7.2 条件指令的语法

没有else的简单条件指令语法如下:

conditional-directivetext-if-trueendif

text-if-true可以是任意文本行,当条件为真时作为makefile的一部分。如果条件为假,则没有任何语句加入makefile。

条件指令复杂一点的语法如下:

conditional-directivetext-if-trueelsetext-if-falseendif

或者:

conditional-directive-onetext-if-one-is-trueelse conditional-directive-twotext-if-two-is-trueelsetext-if-one-and-two-are-falseendif

必要时可以使用多个else conditional-directive语句。一旦有一个给定的条件为truetexit-if-true被使用,其它语句被忽略。如果没有条件为truetext-if-false被使用。text-if-truetext-if-false可以是任意多行的文本。

不管简单条件指令还是复杂条件指令,conditional-directive的语法都相同。有四种不同的指令测试不同的条件。下面是详细描述:

  • ifeq (arg1, arg2)
    ifeq ‘arg1’ ‘arg2’
    ifeq “arg1” “arg2”
    ifeq “arg1” ‘arg2’
    ifeq ‘arg1’ “arg2”

    arg1arg2中的变量引用全部展开,然后比较它们。如果完全相同,text-if-true有效,否则text-if-false有效(如果有的话)。
    你经常想测试一个变量是否是一个非空值。如果这个值是很复杂的变量和函数展开得到的,这些展开可能包含空格字符(不为空),却被你认为是空。然而,可以使用strip函数避免将空格字符当作非空值。例如:

    ifeq ($(strip $(foo)),)text-if-emptyendif

    即使$(foo)包含空格字符,texit-if-empty仍然会执行。

  • ifneq (arg1, arg2)
    ifneq ‘arg1’ ‘arg2’
    ifneq “arg1” “arg2”
    ifneq “arg1” ‘arg2’
    ifneq ‘arg1’ “arg2”

    展开arg1arg2中的所有变量引用都展开并比较它们。如果它们不同,text-if-true会生效,否则text-if-false会生效(如果有的话)。

  • ifdef variable-name

    ifdef使用变量名作为参数,而不是变量的引用。如果变量的值非空,text-if-true生效,否则text-if-false生效(如果有的话)。未定义的变量值为空。文本variable-name被展开,因此它可以是一个变量或函数,它们展开成一个变量名。例如:

    bar = truefoo = barifdef $(foo)frobozz = yesendif

    变量引用$(foo)被展开成bar,它被当作变量名。变量bar不会被展开,但是它的值用于检查其是否为空。

    注意ifdef只是测试一个变量是否有值,它不会展开变量去查看其值是否为空。所有已定义的变量用ifdef都会返回true,除了像foo =这样的语句。例如,使用ifeq ($(foo))测试一个空值:

    bar =foo = $(bar)ifdef foofrobozz = yeselsefrobozz = noendif

    frobozz设置为yes,而:

    foo =ifdef foofrobozz = yeselsefrobozz = noendif

    设置frobozzno

  • ifndef variable-name

    如果变量variable-name有一个空值,text-if-true生效,否则text-if-false生效(如果有的话)。展开和测试variable-name的规则与ifdef指令完全相同。

在条件指令行的开始运行有额外的空格,并且会被忽略,但是不允许有tab。(如果有tab,会被当作recipe的一部分。)另外,除了在指令名或参数名之间插入空格或tab,在其它地方额外的空格和tab并没有什么影响。以#开始的注释可以出现在行末尾。

其它两个作为条件语句的指令是elseendif。它俩都是以这一个单词作为指令,没有参数。行开头的空格以及行末的空格和tab被忽略。以#开始的注释可以出现在行末。

条件指令影响make所使用的makefile的内容。如果条件为真,text-if-true成为makefile的一部分;如果条件为假,text-if-false成为makefile的一部分。

当读取makefile时,make计算执行条件。因此,不能使用自动变量用于测试条件,因为在recipes运行之前它们还没定义。

为了避免产生困惑,不允许在一个makefile文件中开始条件指令,在另一个makefile文件中结束条件指令。但是,你可以在条件指令中使用include指令。不要试图在包含文件中终止这个条件指令。

7.3 测试标识条件指令

你可以写一个条件指令用于测试make命令标志,如-t被用于变量MAKEFLAGS和函数findstring中。当touch不足以使一个文件更新时,这很有用。

函数findstring用于确定一个字符串是否包含在另一个字符串中。如果要测试-t标志,使用t作为第一个字符串,而MAKEFLAGS的值作为另一个字符串。

例如,下面是如何使用ranlib -t标记文件被更新:

archive.a: ...ifneq (,$(findstring t,$(MAKEFLAGS)))        +touch archive.a        +ranlib -t archive.aelse        ranlib archive.aendif

前缀+标记这些recipe行为递归,因此尽管使用-t标志,这些recipe也会被执行。

原创粉丝点击