🌝

Makefile 语法学习

Posted at — May 15, 2022

变量赋值

简单赋值(:=)

一旦 make 读入该变量的定义语句,赋值运算符右边部分会立刻扩展,而扩展后的文本会被存储成该变量的值1

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

等同于:

1
2
x := later
y := foo bar

递归变量(=)

扩展的动作会被延迟到该变量被使用的时候进行。

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

条件变量(?=)

只会在变量的值尚不存在是进行赋值操作。

条件语句

ifeq:是否相等

1
2
3
ifeq (arg1, arg2)
	...
endif

ifneq:是否不等

1
2
3
4
5
ifneq (arg1, arg2)
	...
else
	...
endif

ifdef:是否有值

1
2
3
ifdef variable-name
	...
endif

ifndef:是否未赋值

1
2
3
4
5
6
7
8
ifndef branch
    br = master
else
    br = ${branch}
endif

demo:
	@echo $(br)
1
2
3
4
5
$ make demo
master

$ make demo branch=dev
dev

在 makefile 中执行 shell

1
CUR_DIR=$(shell pwd)

注意,在使用 $ 时,需要写为 $$。因为 $ 在 makefile 中有特殊含义,使用前需要转义。

1
2
3
4
tag=2.0

all:
	@echo $(shell echo ${tag} | awk -F '.' '{print "v"$$1}')

@ 关闭回显

make 默认会在执行 recipe 打印 recipe 内容(Recipe Echoing)。要关闭回显,使用@ 2

1
2
3
4
5
6
7
demo_a:
	@sh -c "echo hello,"
	@echo "world!"

demo_b:
	sh -c "echo hello,"
	echo "world!"
1
2
3
4
5
6
7
8
9
$ make demo_a
hello,
world!

$ make demo_b
sh -c "echo hello,"
hello,
echo "world!"
world!

缩进

recipe 前使用 tag,条件语句前使用空格,否则会报错。

1
2
3
4
5
demo:
	@echo hello, world!
    ifeq (arg1, arg2)
		@echo do something
    endif

这里 ifeqendif 缩进用空格。

在 recipe 中使用变量

1
2
3
recipe: 
	$(eval var=value)
	@echo ${var}

如果没有 eval,则不能得到期望结果3

  1. 写成 var=value

make recipe 无输出。

1
2
3
recipe: 
	var=value
	@echo ${var}

该写法等同于4

1
2
$ sh -c 'var=value'
$ sh -c 'echo ${var}'

The recipe of a rule consists of one or more shell command lines to be executed, one at a time, in the order they appear.

  1. 写成 var=value

make recipe 会报错:make: var: No such file or directory。

1
2
3
recipe: 
	var = value
	@echo ${var}

该写法等同于:

1
2
3
$ sh -c 'var = value'
sh: var: command not found
$ sh -c 'echo ${var}'

.PHONY 意义及用法

我们经常在 makefile 文件中看到类似下面的代码:

1
2
3
.PHONY: clean
clean:
	rm *.o temp

要讲清楚 .PHONY 的意义及用法,先要理解 makefile 中 rule 的概念。一个 rule 由 target 和 recipe组成:

1
2
3
4
target: prerequisites ...
	recipe
	recipe
	...

target 可以是文件名,可执行程序,以及更常见操作名(the name of an action)。而当 target 的含义是操作名的时候,这种 target 需要用 .PHONY 来指明是 phony target。

如果不用 .PHONY,当当前目录存在与 target 同名的文件时,make target 不会执行,并提示 make: `xxx’ is up to date.