Makefile学习笔记(7)——多行变量,环境变量,目标变量,模式变量,条件判断

本文详细介绍了Makefile中的多行变量、环境变量、目标变量、模式变量及条件判断的用法。通过实例解析了如何使用define定义多行命令,环境变量的覆盖规则,目标变量的局部作用域,模式变量批量处理目标,以及ifeq等条件表达式的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

继续makefile变量的学习

7.1多行变量

使用define关键字设置变量的值可以有换行,有利于定义一系列的命令,例如前面的“命令包”,define 指示符后面跟的是变量的名字,而重起一行定义变量的值,定义是以 endef 关键字结束。其工作方式和“=”操作符一样。变量的值可以包含函数、命令、文字,或是其它变量。因为命令需要以[Tab]键开头,所以如果你用 define 定义的命令变量中没有以[Tab]键开头,那么 make 就不会把其认为是命令。

下面的这个示例展示了 define 的用法:

define two-lines
echo foo
echo $(bar)
endef

foo += "lujw"
bar += "this is a test"

.PHONY:print
print:
	@$(two-lines)

可以自己尝试运行下看能输出什么结果。

7.2环境变量

      并不推荐把许多的变量都定义在系统环境中,这样,在我们执行不用的 Makefile 时,拥有的是同一套系统变量,这可能会带来更多的麻烦。这里只讲解下环境变量的作用。

      make 运行时的系统环境变量可以在 make 开始运行时被载入到 Makefile 文件中,但是如果 Makefile 中已定义了这个变量,或是这个变量由 make 命令行带入,那么系统的环境变量的值将被覆盖。(如果 make 指定了“-e”参数,那么,系统环境变量将覆盖 Makefile 中定义的变量),可以与之前的override指示符配合使用达到某种特定的情况需求

    因此,在环境变量中设置了“CFLAGS”环境变量,就可以在所有的 Makefile 中使用这个变量了。这对于使用统一的编译参数有比较大的好处。如果 Makefile 中定义了 CFLAGS,那么则会使用 Makefile中的这个变量,如果没有定义则使用系统环境变量的值,一个共性和个性的统一,很像“全局变量”和“局部变量”的特性。当 make 嵌套调用时(参见前面的“嵌套调用”章节),上层 Makefile 中定义的变量会以系统环境变量的方式传递到下层的 Makefile 中。当然,默认情况下,只有通过命令行设置的变量会被传递。而定义在文件中的变量,如果要向下层 Makefile 传递,则需要使用 exprot 关键字来声明。

7.3目标变量

如果说前面的变量都是“全局变量”,那么目标变量就相当于“局部变量”,它可以和“全局变量同名”。作用范围只在这条规则以及连带规则中,所以其值也只在作用范围内有效。而不会影响规则链以外的全局变量的值。

语法为:

<target...>:<variable-assignment>
<target...>:override <variable-assignment>

<variable-assignment>可以是前面讲过的各种赋值表达式,如“=”、“:=”、“+=”或是“?=”。第二个语法是针对于 make 命令行带入的变量,或是系统环境变量。给个例子:

CC =gcc
main:CFLAGS=-g -o
main:main.o fun.o 
	$(CC) $(CFLAGS) main.o fun.o
main.o:CFLAGS=-g -c
main.o:main.c
	$(CC) $(CFLAGS) main.c 
fun.o:CFLAGS=-g -c
fun.o:fun.c
	$(CC) $(CFLAGS) fun.c

当我执行make -n只输出打印时

可以看出CFLAGS的不同,例子本身没有实际意义,只是看目标变量的使用。

7.4模式变量

在 GNU 的 make 中,还支持模式变量(Pattern-specificVariable),通过上面的目标变量中,变量可以定义在某个目标上。模式变量的好处就是,可以给定一种“模式”,可以把变量定义在符合这种模式的所有目标上。make 的“模式”一般是至少含有一个“%”的,所以,我们可以以如下方式给所有以[.o]结尾的目标定义目标变量:
%.o:CFLAGS=-O
同样,模式变量的语法和“目标变量”一样:
<pattern...>:<variable-assignment>
<pattern...>:override<variable-assignment>
override 同样是针对于系统环境传入的变量,或是 make 命令行指定的变量。


7.5条件判断


使用条件判断,可以让 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

上例子中“foo”可以根据变量“$(CC)”值来选取不同的函数库来编译程序,和c语言中if else语句类似。

另外一种写法

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)

这样子更简洁

 

语法

<conditional-directive>
    <text-if-true>
endif
以及:
<conditional-directive>
    <text-if-true>
else
    <text-if-false>
endif
其中<conditional-directive>表示条件关键字,这个关键字有四个

第一个就是"ifeq"

具体写法为以下5种中的任意一种

ifeq(<arg1>,<arg2>)
ifeq'<arg1>''<arg2>'
ifeq"<arg1>""<arg2>"
ifeq"<arg1>"'<arg2>'
ifeq'<arg1>'"<arg2>"

比较参数“arg1”和“arg2”的值是否相同。当然,参数中我们还可以使用 make 的函数。如:
ifeq($(strip$(foo)),)
    <text-if-empty>
endif

这个示例中使用了“strip”函数,如果这个函数的返回值是空(Empty),那么<text-if-empty>就生效。

第二个就是"ifneq"

其比较参数“arg1”和“arg2”的值是否相同,如果不同,则为真。和“ifeq”类似。

第三个条件关键字是“ifdef”

语法是:

ifdef<variable-name>

如果变量<variable-name>的值非空,那到表达式为真。否则,表达式为假。当然,<variable-name>同样可以是一个函数的返回值。注意,ifdef 只是测试一个变量是否有值,其并不会把变量扩展到当前位置。看例子

示例一:
bar=
foo=$(bar)
ifdef foo
  frobozz=yes
else
  frobozz=no
endif
示例二:
foo=
ifdef foo
  frobozz=yes
else
  frobozz=no
endif

第一个例子中,“$(frobozz)”值是“yes”,第二个则是“no”。

第四个条件关键字是“ifndef”, 和“ifdef”是相反的意思。

在<conditional-directive>,“else”,“endif”这一行上,只要不是以[Tab]键开始,多余的空格是被允许的。注释符“#”同样也是安全的。

值得注意的是不要把自动化变量(如“$@”等)放入条件表达式中,因为自动化变量是在运行时才有的。而且,为了避免混乱,make 不允许把整个条件语句分成两部分放在不同的文件中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值