tartarus's bolg tartarus's bolg
  • Linux and Unix Guide
  • CMake
  • gcc
  • gdb
  • bash
  • GNU Make
  • DDCA-ETH
  • CS106L
  • CS144
  • NJU PA
  • NJU OS(jyy)
  • C
  • C++
  • Python
  • reveal-md
  • LaTex
  • Paper Reading
  • TBD
  • Linux and Unix Guide
  • CMake
  • gcc
  • gdb
  • bash
  • GNU Make
  • DDCA-ETH
  • CS106L
  • CS144
  • NJU PA
  • NJU OS(jyy)
  • C
  • C++
  • Python
  • reveal-md
  • LaTex
  • Paper Reading
  • TBD
  • pdb

  • make

    • 1.0 声明😁
    • 2.0 makefile介绍
    • 3.0 书写makefile
    • 3.0 书写规则
    • 4.0 书写命令
    • 5.0 使用变量
      • 变量的基础
      • 变量中的变量(通常使用方法二)
      • 变量的高级用法
      • 追加变量
      • override 指令
      • 目标变量
      • 模式变量
    • 6.0 使用条件判断
    • 7.0 使用函数
    • 8.0 make的运行
  • cmake

  • Linux and Unix

  • Basic_Software
  • make
tartarus
2023-08-30
目录

5.0 使用变量

# 使用变量

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

# 变量的基础

变量在声明时需要给予初值,而在使用时,需要给在变量名前加上 $ 符号,但最好用小括号 () 或是大括号 {} 把变量给包括起来。如果要使用真实的 $ 字符,那么你需要用 $$ 来表示。

# 变量中的变量 (通常使用方法二)

用变量来定义变量的方法一:
简单的使用 = 号,在 = 左侧是变量,右侧是变量的值,右侧变量的值可以定义在文件的任何一处,也就是说,右侧中的变量不一定非要是已定义好的值,其也可以使用后面定义的值。如:

foo = $(bar)
bar = $(ugh)
ugh = Huh?

all:
    echo $(foo)
1
2
3
4
5
6

我们执行 “make all” 将会打出变量 $(foo) 的值是 Huh? ( $(foo) 的值是 $(bar) , $(bar) 的值是 $(ugh) , $(ugh) 的值是 Huh? )可见,变量是可以使用后面的变量来定义的。

这种方法的优点:可以把变量的真实值推到后面来定义,如

CFLAGS = $(include_dirs) -O
include_dirs = -Ifoo -Ibar
1
2

当 CFLAGS 在命令中被展开时,会是 -Ifoo -Ibar -O 。

这种方法的缺点:但这种形式也有不好的地方,那就是递归定义,如:

CFLAGS = $(CFLAGS) -O
1

用变量来定义变量的方法二:

为了避免上面的这种方法,我们可以使用 make 中的另一种用变量来定义变量的方法。这种方法使用的是 := 操作符,如:

x := foo
y := $(x) bar
x := later
1
2
3

其等价于:

y := foo bar
x := later
1
2

优点:这种方法,前面的变量不能使用后面的变量,只能使用前面已定义好了的变量。

使用变量中的变量来获得 space:

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

nullstring 是一个 Empty 变量,其中什么也没有,而我们的 space 的值是一个空格。因为在操作符的右边是很难描述一个空格的,这里采用的技术很管用,先用一个 Empty 变量来标明变量的值开始了,而后面采用 “#” 注释符来表示变量定义的终止,这样,我们可以定义出其值是一个空格的变量。

请注意这里关于 “#” 的使用,注释符 “#” 的这种特性值得我们注意,如果我们这样定义一个变量:
dir := /foo/bar # directory to put the frobs in

dir 这个变量的值是 “/foo/bar”,后面还跟了 4 个空格,如果我们这样使用这个变量来指定别的目录 ——“$(dir)/file” 那么就完蛋了。

?= : 如果变量没有被定义过,就使用该定义,否则什么也不做。

FOO ?= bar
1

等价于:

ifeq ($(origin FOO), undefined)
    FOO = bar
endif
1
2
3

# 变量的高级用法

高级用法一:变量值的替换

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

举例:

foo := a.o b.o c.o
bar := $(foo:.o=.c)
1
2

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

另外一种变量替换的技术是以静态模式(参见前面章节)定义的,如:

foo := a.o b.o c.o
bar := $(foo:%.o=%.c)
1
2

但是这要求变量 $(foo) 中所有的值都要以.o 结尾并且模式中必须包含一个 % 字符。

高级用法二:把变量的值再当成变量

x = y
y = z
a := $($(x))
1
2
3

# 追加变量

使用 += 操作符给变量追加值:

  • 如果变量之前没有定义过,那么, += 会自动变成 =
  • 如果前面有变量定义,那么 += 会继承于前次操作的赋值符
    • 如果前一次的是 := ,那么 += 会以 := 作为其赋值符
    • 如果前一次的是 = ,那么 += 会以 = 作为其赋值符
      (由于前次的赋值符是 = ,所以 += 也会以 = 来做为赋值,那么岂不会发生变量的递补归定义,这是很不好的,所以 make 会自动为我们解决这个问题,我们不必担心这个问题。)

举例:

variable := value
variable += more
1
2

等价于:

variable := value
variable := $(variable) more
1
2

# override 指令

override 同样是针对于系统环境传入的变量,或是 make 命令行指定的变量。

如果有变量是通常 make 的命令行参数设置的,那么 Makefile 中对这个变量的赋值会被忽略。如果你想在 Makefile 中设置这类参数的值,那么,你可以使用 “override” 指令。其语法是:

override <variable> = <value>
override <variable> := <value>
override <variable> += <more text>
1
2
3

对于多行的变量定义,我们用 define 指令,在 define 指令前,也同样可以使用 override 指令,如:

override define foo
bar
endef
1
2
3

# 目标变量

前面我们所讲的在 Makefile 中定义的变量都是 “全局变量”,在整个文件,我们都可以访问这些变量。当然,“自动化变量” 除外,如 $< 等这种类量的自动化变量就属于 “规则型变量”,这种变量的值依赖于规则的目标和依赖目标的定义。

同样可以为某个目标设置局部变量,这种变量被称为 “Target-specific Variable”,它可以和 “全局变量” 同名,因为它的作用范围只在这条规则以及连带规则中,所以其值也只在作用范围内有效。而不会影响规则链以外的全局变量的值。

语法:

<target ...> : <variable-assignment>
<target ...> : overide <variable-assignment>
1
2

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

这个特性非常的有用,** 当我们设置了这样一个变量,这个变量会作用到由这个目标所引发的所有的规则中去。** 如:

prog : CFLAGS = -g
prog : prog.o foo.o bar.o
    $(CC) $(CFLAGS) prog.o foo.o bar.o

prog.o : prog.c
    $(CC) $(CFLAGS) prog.c

foo.o : foo.c
    $(CC) $(CFLAGS) foo.c

bar.o : bar.c
    $(CC) $(CFLAGS) bar.c
1
2
3
4
5
6
7
8
9
10
11
12

在这个示例中,不管全局的 $(CFLAGS) 的值是什么,在 prog 目标,以及其所引发的所有规则中(prog.o foo.o bar.o 的规则), $(CFLAGS) 的值都是 -g

# 模式变量

通过上面的目标变量中,我们知道,变量可以定义在某个目标上。模式变量的好处就是,我们可以给定一种 “模式”,可以把变量定义在符合这种模式的所有目标上。

make 的 “模式” 一般是至少含有一个 % 的,所以,我们可以以如下方式给所有以 .o 结尾的目标定义目标变量:

%.o : CFLAGS = -O
1

同样,模式变量的语法和 “目标变量” 一样:

<pattern ...> : <variable-assignment>
<pattern ...> : override <variable-assignment>
1
2

override 同样是针对于系统环境传入的变量,或是 make 命令行指定的变量。

上次更新: 12/27/2023, 8:55:47 AM
4.0 书写命令
6.0 使用条件判断

← 4.0 书写命令 6.0 使用条件判断→

Theme by Vdoing | Copyright © 2023-2023 tartarus | CC BY-NC-SA 4.0
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式