Makefile——变量

Makefile中关于变量的语法规则

1、使用 = 定义的变量为延时赋值型变量,可以把变量的放到后面定义。

一个简单的例子:

foo = $(bar) 
bar = Huh? 
all: 
    @echo $(foo)

先说明一下,$(xxx)表示取变量xxx的值

  • 执行make将会输出 Huh?。
  • 当make读到foo = $(bar)时,确定foo 的值是 $(bar),但并不立即展开$(bar).
  • 然后读到bar = Huh?,确定bar的值是Huh?.
  • 然后再执行规则all:的命令列表时才需要展开$(foo),得到$(bar),再展开$(bar),得到Huh?。
  • 因此,虽然bar的定义写在foo之后,$(foo)展开还是能够取到$(bar)的值。
main.o: main.c 
    $(CC) $(CFLAGS) $(CPPFLAGS) -c $<
    CC = gcc
    CFLAGS = -O -g
    CPPFLAGS = -Iinclude

编译命令可以展开成gcc -O -g -Iinclude -c main.c。
通常把CFLAGS定义成一些编译选项,例如-O、-g等,而把CPPFLAGS定义成一些预处理选项,例如-D、-I等。
用 = 号定义变量的延迟展开特性也有坏处,就是有可能写出无穷递归的定义,例如:

A = $(B)
B = $(A)

当然,make有能力检测出这样的错误而不会陷入死循环。


2、使用 := 定义的变量为立即赋值型变量,变量值当即确定。
有时候我们希望make在遇到变量定义时立即展开,可以用 := 运算符,例如

x := foo
y := $(x) bar
all: @echo "-$(y)-"

当make读到 y := $(x) bar定义时,立即把$(x)展开,使变量y的取值是foo bar。
如果把这两行颠倒过来:

y := $(x) bar
x := foo

那么当make读到 y := $(x) bar时,x还没有定义,展开为空值,所以y的取值是 bar。
注意bar前面有个空格

一个变量的定义从 = 后面的第一个非空白字符开始(从$(x)的$开始),包括后面的所有字符,直到注释或换行之前结束。

如果要定义一个变量的值是一个空格,

nullstring := 
space := $(nullstring) # end of the line

nullstring的值为空,space的值是一个空格。
后面写个注释是为了增加可读性,如果不写注释就换行,则很难看出$(nullstring)后面有个空格。


3、?= 为条件延时赋值运算符,变量已经定义过才会延时赋值

foo ?= $(bar)

如果foo没有定义过,那么?=相当于=,定义foo的值是$(bar),但不立即展开;
如果先前已经定义了foo,则什么也不做,不会给foo重新赋值。


4、+=运算符可以给变量追加值

objects = main.o
objects += $(foo)
foo = foo.o bar.o

object是用=定义的,+=仍然保持=的特性。
objects的值是main.o $(foo)(注意$(foo)前面自动添一个空格),但不立即展开,等到后面需要展开$(objects)时会展开成main.o foo.o bar.o。

objects := main.o
objects += $(foo)
foo = foo.o bar.o

object是用 := 定义的,+= 保持 := 的特性
objects的值是main.o $(foo),立即展开得到main.o(这时foo还没定义)。注意main.o后面的空格仍保留。
如果变量还没有定义过就直接用+=赋值,那么+=相当于=。


5、特殊变量$@、$<、$?、$^

  • $@,表示规则中的目标
  • $<,表示规则中的第一个条件
  • $?,表示规则中所有比目标新的条件,组成一个列表,以空格分隔
  • $^,表示规则中的所有条件,组成一个列表,以空格分隔
main: main.o stack.o maze.o 
    gcc main.o stack.o maze.o -o main

可以改写成

main: main.o stack.o maze.o 
    gcc $^ -o $@

$^展开为 main.o stack.o maze.o
$@展开为main

这样即使以后又往条件里添加了新的目标文件,编译命令也不需要修改,减少了出错的可能。

$?变量也很有用,有时候希望只对更新过的条件进行操作,例如有一个库文件libsome.a依赖于几个目标文件:

libsome.a: foo.o bar.o lose.o win.o 
    ar r libsome.a $? 
    ranlib libsome.a

这样,只有更新过的目标文件才需要重新打包到libsome.a中,没更新过的目标文件原本已经在libsome.a中了,不必重新打包。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值