makefile 学习笔记 三:makefile 语句

本文介绍了Makefile中的条件语句及其使用方法,包括如何根据不同条件选择性地执行某些任务,以及如何通过条件语句控制链接库的选择。还讨论了条件语句的语法和测试标志的方法。

一、条件语句

条件指令会导致根据变量的值服从或忽略 makefile 的一部分。条件可以将一个变量的值与另一个变量的值进行比较,或者将变量的值与常量字符串进行比较。条件控制 make 文件中实际"sees"的内容,因此它们不能用于在执行时控制配方。

1、条件句示例

下面的条件示例告诉 make,如果 CC 变量是 “gcc”,则使用一组不同的库,否则则使用另一组库。它的工作原理是控制两个配方行中的哪一个将用于该规则。结果是"CC=gcc"作为参数,不仅可以更改使用哪个编译器,还可以更改链接的库。

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 指令开始条件,并指定条件。它包含两个参数,用逗号分隔,用括号括起来。对两个参数执行变量替换,然后对它们进行比较。如果两个参数匹配,则遵循 ifeq 后面的 makefile 行;否则,它们将被忽略。

如果前一个条件失败,则 else 指令会导致遵循以下行。在上面的示例中,这意味着只要不使用第一个替代命令,就会使用第二个备选项链接命令。在条件句中使用else是可选的

endif 指令结束条件指令。每个条件都必须以 endif 结尾。无条件的makefile文本如下。

如本例所示,条件作用于文本级:条件语句的行被视为 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 = -lgnu
normal_libs =

ifeq ($(CC),gcc)
  libs=$(libs_for_gcc)
else
  libs=$(normal_libs)
endif

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

2、条件语句的语法

没有其他条件的简单条件的语法如下:

conditional-directive
text-if-true
endif

text-if-true可以是任何文本行,如果条件为真,则被视为makefile的一部分。如果条件为 false,则不使用任何文本。

复杂条件的语法如下所示:

conditional-directive
text-if-true
else
text-if-false
endif

conditional-directive-one
text-if-one-is-true
else conditional-directive-two
text-if-two-is-true
else
text-if-one-and-two-are-false
endif

可以根据需要有尽可能多的"else 条件指令"子句。一旦给定条件为真,text-if-true就会被使用,而不使用其他子句;如果没有条件为真,则使用text-if-false。text-if-true和text-if-false可以是任意数量的文本行。

条件指令的语法是相同的,无论条件是简单的还是复杂的;在else或not后面。有四种不同的指令用于测试不同的条件。这是他们的一个表格:

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
  • 将计算text-if-empty,即使$(foo)的展开包含空白字符。
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
  • ifdef 形式以变量的名称作为参数,而不是对变量的引用。如果该变量的值为非空值,则text-if-true有效;否则,text-if-false(如果有的话)有效。未定义的变量值为空。文本变量名是展开的,因此它可以是展开为变量名的变量或函数。例如:
bar = true
foo = bar
ifdef $(foo)
frobozz = yes
endif
  • 变量引用 $(foo) 被展开,产生bar,这被认为是变量的名称。变量 bar 不会展开,但会检查它的值,以确定它是否为非空。
  • 注意,ifdef只测试变量是否有值。它不会展开变量以查看该值是否为非空值。因此,使用ifdef的测试对于除 foo =. 之外的所有定义都返回true。要测试空值,使用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(如果有的话)有效。变量名的扩展和测试规则与ifdef指令相同。

在条件指令行开始处允许和忽略额外的空格,但不允许使用制表符(如果行以一个制表符开始,它将被认为是规则的配方的一部分)。除此之外,插入额外的空格或制表符时,除了指令名或参数内,其他地方都不会有任何效果。以"#"开头的注释可能会出现在行的末尾。

在条件句中起作用的另外两个指令是else和endif。这些指令都写成一个单词,没有参数。行首允许和忽略额外的空格,行尾允许空格或制表符。以“#”开头的注释可能出现在行尾。

条件影响makefile的哪一行使用。如果条件为真,make 将读取 text-if-true 作为 makefile 的一部分;如果条件为 false,则 make 将完全忽略这些行。因此,makefile的语法单元(如规则)可以安全地拆分到条件的开头或结尾。

make 在读取 makefile 时计算条件。因此,您不能在条件测试中使用自动变量,因为只有在运行配方时才会定义这些变量。

为了防止不可容忍的混乱,不允许在一个makefile中启动一个条件文件,而在另一个makefile中结束它。但是,如果您不尝试在包含的文件中终止该条件,则可以在条件文件中编写include指令。

3、测试标志的条件

您可以编写一个条件,通过使用变量 MAKEFLAGS 和 findstring 函数来测试命令标志,例如 -t。当 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"标志,它们仍将被执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值