Makefile 变量--第三天

Makefile 变量

变量的概念

​ 在 Makefile中的定义的变量,就像是C/C++语言中的宏一样,他可以代表一个文本字符串也可以是数字,在Makefile中执行的时候其会自动原模原样地展开在所使用的地方。其与C/C++所不同的是,你可以在Makefile中改变其值。在Makefile中,变量可以使用在“目标”,“依赖目标”,“命令”或是 Makefile的其它部分b中。

变量的命名

变量的命名字可以包含字符、数字,下划线(可以是数字开头),但不应该含有“:”、“#”、“=”或是空字符(空格、回车等)。变量区分大小写,传统的Makefile的变量名是全大写的命名方式,通常使用大小写搭配的方式命名变量例如 Flags。这样可以避免和系统的变量冲突,而发生意外的事情。还有一些如“ < ” 、 “ <”、“ <@” “^”等自动化变量。

变量的使用

变量在声明时需要给予初值,而在使用该变量时,需要给在变量名前 加上“ ” 符 号 , 但 最 好 用 小 括 号 “ ( ) ” 或 是 大 括 号 “ ” 把 变 量 给 包 括 起 来 , 一 般 用 括 起 来 。 如 果 你 要 使 用 真 实 的 “ ”符号,但最好用小括号“()”或是大括号“{}”把变量给包括起来,一般用{}括起来。如果你要使用真实的“ 使”字符,那么你需要用“$$”来表示。变量可以使用在许多地方,如规则中的“目标”、“依赖”、“命令”以及新的变量中。

obj=main.c
src=${obj}
#展开src = main.c

在定义变量的值时,我们可以使用其它变量来构造变量的值,在Makefile中有两种方式来在用变量定义变量的值。
先看第一种方式,也就是简单的使用“=”号,在“=”左侧是变量,右侧是变量的值,右侧变量的值可以定义在文件的任何一处,也就是说,右侧中的变量不一定非要是已定义好。使用这种方式要注意,变量的值是最终赋值的值,例如

inc=${src}
src=${obj}
obj= main.c

all:
	echo ${inc}

下面看个例程

A=${B}
B=${A}

这会让make陷入无限的变量展开过程中去,当然,我们的make是有能力检测这样的定义,并会报错。还有就是如果在变量中使用函数,那么,这种方式会让我们的make运行时非常慢,更糟糕的是,他会使用得两个make的函数“wildcard”和“shell”发生不可预知的错误。因为你不会知道这两个函数会被调用多少次。

我们通过使用“:=”操作符来定义变量,

foo1:=blue
foo2:=${foo1} pig
all:
	echo ${foo2}
#等价于 --> blue pig
#前后的变量不能使用后面变量的值
foo2:=${foo1} pig
foo1:=blue
all:
	echo ${foo2}
#等价于 -->  pig	

还有一个比较有用的操作符是“?=”,先看示例:

FOO ?= bar

其含义是,如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语将什么也不做,其等价于:
ifeq ($(origin FOO), undefined)
FOO = bar
endif

变量的替换

我们可以替换变量中的共有的部分,其格式是“ ( v a r : a = b ) ” 或 是 “ (var:a=b)”或是“ (var:a=b){var:a=b}”,其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束符”。

foo := a.o b.o c.o
bar := ( f o o : . o = . c ) 这 个 示 例 中 , 我 们 先 定 义 了 一 个 “ (foo:.o=.c) 这个示例中,我们先定义了一个“ (foo:.o=.c)(foo)”变量,而第二行的意思是把“ ( f o o ) ” 中 所 有 以 “ . o ” 字 串 “ 结 尾 ” 全 部 替 换 成 “ . c ” , 所 以 我 们 的 “ (foo)”中所有以“.o”字串“结尾”全部替换成“.c”,所以我们的“ (foo).o.c(bar)”的值就是“a.c b.c c.c”。

另外一种变量替换的技术是以“静态模式”(参见前面章节)定义的,如:foo := a.o b.o c.o
bar := $(foo:%.o=%.c)

override指示符

通常在执行 make 时,如果通过命令行定义了一个变量,那么它将替代在 Makefile中出现的同名变量的定义。
就是说,对于一个在 Makefile 中使用常规方式(使用“=”、“:=”或者“define”)定义的变量,我们可以在执行 make 时通过命令行方式重新指定这个变量的值,命令行指定的值将替代出现在 Makefile 中此变量的值。
如果不希望命令行指定的变量值替代在 Makefile 中的变量定义,那么我们需要在 Makefile 中使用指示符“override”来对这个变量进行声明。

override作用
  1. 保护makefile中定义的变量的值;
  2. 提供一种在makefile中增加或者修改命令行参数的方式;

​ 实际情况下,我们经常会有这种需求:通过命令行指定一些附加的参数选项,对于一些通用的参数选项在makefile中指定.

保护makefile中定义变量值示例
1.1 没有使用override的情况

make命令行指定的变量值将会覆盖makefile中定义的同名的变量值

SRCS := A.c B.c C.c

all:
	@echo "SRCS: " $(SRCS)
#执行make  SRC=no
#输出的值为no
1.2 使用override的情况

make命令行指定的变量值将不会覆盖makefile中定义的同名的变量值,所以override有保护makefile中变量值不被命令行参数修改的作用。

override SRCS := A.c B.c C.c

all:
	@echo "SRCS: " $(SRCS)
1.3 override追加变量
#使用override进行追加的变量的原来指定的值不会被命令行参数覆盖,而且会追加命令行指定的值
override CFLAGS += -g

all:
	@echo $(CFLAGS)

变量的追加

通过使用“+=”操作符来对一个变量进行追加赋值

例如

src=main.o led.o key.o
src+=muc.o
all:
	echo ${src}
#等价于:-->main.o led.o key.o muc.o	

环境变量

make 运行时的系统环境变量可以在make开始运行时被载入到Makefile文件中,但是如果Makefile中已定义了这个变量,或是这个变量由make命令行带入,那么系统的环境变量的值将被覆盖。(如果make指定了“-e”参数,那么,系统环境变量将覆盖Makefile中定义的变量)

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

define 用法

makefile里可能会用到define来打包一些可能会重用的指令,但是因为makefile里实际上会重用代码的情况并不多…所以,define是一个没怎么设计的挺难用的东西;有一点需要注意的是在define-endef范围内的变量定义和指令的执行,在该范围内,变量定义是无效的,在define段执行时回座位字符串展开;指令的执行则是需要注意一下cmd ( s h e l l c m d ) 的 区 别 , 区 别 是 ‘ c m d ‘ 在 执 行 到 当 前 指 令 的 时 候 不 展 开 , 而 (shell cmd)的区别,区别是`cmd`在执行到当前指令的时候不展开,而 (shellcmd)cmd(shell cmd)在执行到当前指令的时候是展开为指令结果的;

define 类似定义函数

define output
	A=pwd#作为字符串输出
	A=`pwd`#作为字符串输出
	A=$(shell pwd)#只有这个A的值是pwd展开之后的值,但是!
	echo $(A)#这句的输出是空的,上一句A=$(shell pwd)并不是存在一个被赋值的变量A,
	#而是define在执行的时候A=是一个字符串,然后$(shell pwd)在echo语句中也被直接展开为了字符串的形式;
	echo pwd#输出是echo pwd pwd,也就是pwd不展开为shell指令
	echo `pwd`#输出是echo `pwd` a/b/c,也就是先输出指令字符串,随后切到shell执行pwd
	echo $(shell pwd)#输出是echo a/b/c a/b/c,在这句指令显示的阶段$(shell pwd)就已经展开为对应的字符串了
	
endef
all:
	$(call output) 

模式变量

在GNU的make中,还支持模式变量(Pattern-specific Variable),通过上面的目标变量中,我们知道,变量可以定义在某个目标上。模式变量的好处就是,我们可以给定一种“模式”,可以把变量定义在符合这种模式的所有目标上。

我们知道,make的“模式”一般是至少含有一个“%”的,所以,我们可以以如下方式给所有以[.o]结尾的目标定义目标变量:
%.o : CFLAGS = -O
同样,模式变量的语法和“目标变量”一样:
<pattern …> :
<pattern …> : override override

例如

%.o:%.c

自动化变量

$@:表示规则中的目标文件名

$^:表示规则中的所有依赖文件名

$<:表示规则中的第一个依赖文件名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值