makefile中的变量

1.变量的定义和使用

在makefile里的变量只有一种类型,字符串
定义: var = hello
使用: $(var) 或 ${var} 变量名前使用$符号,并用中括号打大括号把变量名括起来。你可以在目标,依赖,更新方法等任何地方使用变量

var = hello
all:
$(info $(var))

$(info xxx) 这是一个函数,具体会在下一章讲, 大致用法就是把XXX替换为你想打印的东西就可以了。

var1 = hello
var2 = $(var1) # var2的值为$(var1),也就是hello
var3 = $(var2) # 同上
all:
$(info $(var3))

2.不同的看待方式

对于makefile里的变量,它确确实实只能存放一种数据类型,那就是字符串,但makefile里的变量既可以是字符串,也可以是字符串数组。或者列表。

var1 = hello
var2 = hello world
all:
$(info $(var1))
$(info $(var2))

我们可以使用一些函数来对数组进行操作。
我们想要获取数组的第n个元素,可以使用word函数来进行操作。

var = hello world  this is a array
element = $(word 3,$(var)) # 取出var里第三个元素 this
all:
$(info $(var))
$(info $(element))

更多的关于列表的函数请看下一章。

3.变量展开

我们先讨论一下的make的工作方式,大致步骤如下:

  1. 读取所有makefile
  2. 读取include的makefile
  3. 初始化文件中的变量
  4. 推导隐式规则
  5. 为所有目标文件创建依赖
  6. 根据依赖关系,决定哪些目标要重新生成
  7. 执行命令

    1-5为第一阶段,6-7为第二阶段。我们在这里只关心和变量有关的工作步骤。

在第一阶段展开的成为立即展开,第二阶段的成为延迟展开

可能这么说你不是很清楚,我们看下具体的例子。

4.延迟展开

直接使用=,这种方式如果赋值的时候右边是其他变量引用或者函数调用之类的,将不会做处理,直接保留原样,在使用到该变量的时候再来进行处理得到变量值(Makefile执行的第二个阶段再进行变量展开得到变量值)

var2= $(var)
all:
$(info $(var2))
var= world

我们根据make的工作方式来看看这个变量到底发生了什么。

  1. 读取这个makefile
  2. 没有include,忽略
  3. 初始化变量,根据从上往下
    1. 定义var2,延迟展开,此时var2的值为$(var)
    2. 定义var,值为world
  4. 推到隐式规则
  5. 创建依赖
  6. 决定生成all这个目标
  7. 执行all里的更新方法,打印var2
    1. $(info $(var2)) 这里要输出var2的值,延迟展开,找到定义var的地方,把var的值拿过来

5.立即展开

赋值使用:=::=,这种方式如果等号右边是其他变量或者引用的话,将会在赋值的时候就进行处理得到变量值。(Makefile执行第一阶段进行变量展开)

var2:= $(var)
all:
$(info $(var2))
var:= world
  1. 读取这个makefile
  2. 没有include,忽略
  3. 初始化变量,根据从上往下
    1. 定义var2,立即展开,值为空,因为找不到var变量
    2. 定义var,值为world
  4. 推到隐式规则
  5. 创建依赖
  6. 决定生成all这个目标
  7. 执行all里的更新方法,打印var2
    1. $(info $(var2)) 这里要输出var2的值 空

6.条件赋值

条件赋值使用?=,如果变量已经定义过了(即已经有值了),那么就保持原来的值,如果变量还没赋值过,就把右边的值赋给变量。

var1 = 100
var1 ?= 200

all:
@echo $(var1) # 100 注释var1 = 100之后为200

7.追加赋值

使用+=在变量已有的基础上追加内容

files = main.cpp
files += hello.cpp

all:
@echo $(files)

8.shell运行赋值

使用!=,运行一个Shell指令后将返回值赋给一个变量

gcc_version != gcc --version
files != ls .

9.定义多行变量

前面定义的变量都是单行的。
变量值有多行,多用于定义shell指令

define <varable_name>  # 默认为 = 
# 变量内容
endef

define <varable_name> :=
# 变量内容
endef

define <varable_name> +=
# 变量内容
endef
var = @echo This is the first line
define var +=
@echo hello
@echo world
@echo 3
endef

all:
$(var)

10.自动变量

$@:目标名
$<:依赖里第一个的名称
$?:比目标新的依赖(依赖的修改时间晚于目标)的名字
$^:所有依赖的名字(去重) 不包含order-only
$+:同上,包含重复,但不包含order-only
$|:order-only
$*:目标主干部分,不包含后缀名

demo:demo.o
gcc -o $@ $<
demo.o:demo.c
gcc -c $<

11.其他

清除变量

var = hello
undefine var

使用环境变量

系统中的环境变量可以直接在Makefile中直接使用,使用方法跟普通变量一样。

all:
@echo $(USERNAME)

变量替换引用

语法:__$(var:a=b)__,意思是将变量var的值当中每一项结尾的a替换为b,直接上例子。

files = main.cpp hello.cpp
objs := $(files:.cpp=.o) # main.o hello.o
# 另一种写法
objs := $(files:%.cpp=%.o)