make 变量¶
1 语法¶
1.1 变量赋值¶
如果没有特殊需求(不需要`=`的递归扩展变量特性),建议使用`:=`赋值方式。
变量的赋值有 4 种符号,如下
- 简单赋值 :=
编程语言中常规理解的赋值方式,只对当前语句的变量有效。
- 递归赋值 =
赋值语句可能影响多个变量,所有目标变量相关的其他变量都受影响。
- 条件赋值 ?=
如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。
- 追加赋值 +=
原变量用空格隔开的方式追加一个新值。
其中 =
允许等号右边的变量在后面出现,且赋值像 C++中引用赋值一样,而 :=
赋值就像 C++中的复制赋值;
- :=
赋值
x:=foo
y:=$(x)b
x:=new
test:
@echo "y=>$(y)"
@echo "x=>$(x)"
- 结果:
y=>foob
x=>new
=
赋值
x=foo
y=$(x)b
x=new
test:
@echo "y=>$(y)"
@echo "x=>$(x)"
- 结果:
y=>newb
x=>new
1.1.1 变量赋值规则总结¶
对于附加运算符“+=”,如果变量之前被设置为简单变量(“:=”或“::=”),则右侧被视为立即 immediate,否则被延迟 deferred。
immediate = deferred
immediate ?= deferred
immediate := immediate
immediate ::= immediate
immediate += deferred or immediate
immediate != immediate
define immediate
deferred
endef
define immediate =
deferred
endef
define immediate ?=
deferred
endef
define immediate :=
immediate
endef
define immediate ::=
immediate
endef
define immediate +=
deferred or immediate
endef
define immediate !=
immediate
endef
1.2 变量的使用¶
变量使用可以用 3 种语法, 相较于 shell,make 中可以使用 $(VAR)
格式
- $VAR
- $(VAR)
- ${VAR}
1.3 替换引用¶
替换引用实际上是 patsubst 函数的简写形式,比如 $(foo:.o=.c)
等价于 $(patsubst %.o,%.c,$(foo))
all:
@echo top makefileg
foo := a.o b.o l.a c.o
bar := $(foo:.o=.c)
$(info bar:$(bar))
输出结果:
[shw@rocky make]$ make
bar:a.c b.c l.a c.c
top makefile
1.4 $
和 $$
的使用区别¶
title: 为什么使用$$
因为在makefile文件中`$`具有特殊函数字符,当我们需要`$`这个字符时,需要通过`$$`来达到转义作用,类似c语言中转义字符`\`。
$(variable)
用在 makefile 变量,而 $$(variable)
用在 shell 变量中
- 示例
var1=hello
test:
echo $var1
var2=2;echo $$var2
2 特殊变量¶
2.1 override 变量¶
- 功能:当在执行 make 时,变量赋值在命令行参数中设置,此时这个变量再次在 makefile 文件中被重新赋值不会覆盖命令行设置的变量值,除非在 makefile 文件中给变量增加 override 指示符。
- 示例:
- make 命令行
## make 命令行指令,变量赋值被单引号包裹
make print 'VAR1=hello'
- makefile 文件
## makefile 文件部分内容
override VAR1=world
print:
echo $(VAR1)
- 执行结果, 设置 override 后 VAR1 被 makefile 重新赋值了,如果没有 override,输出结果会是 hello
$ make print 'VAR1=hello'
echo world
world
2.2 export unexport 变量¶
- 功能:
export
: 导出变量使子 makefile 中能够使用unexport
: 取消导出指定变量- 示例:假设当前目录下有子目录 subdir,且 subdir 中有 makefile 文件
## 父makefile ,-C 指定目录
export VAR1=hello
build:
$(MAKE) -C subdir
## 子makefile,可以使用VAR1变量
build:
echo $(VAR1)
2.3 define 多行变量(仿函数实现方式)¶
- 功能:定义多行变量,自定义函数的实现方式
- 示例
define printparam
@echo "param is"
@echo $1
endef
.PHONY: print
print:
$(call printparam , hello)
- 执行结果
$ make print
param is
hello
2.4 undefine 取消变量¶
- 功能:使之前定义的变量不再生效
- 示例
VAR=123
undefine VAR
2.5 自动化变量¶
$@
: 表示目标文件名$<
: 表示依赖的第一个文件名$^
: 表示所有依赖文件 (每一个文件名之间用空格分隔),会去除重复文件名$+
: 与$^
类似,但会保留重复文件名- 示例
main:main.o math.o
g++ $^ -o $@
main.o:main.cpp math.h
g++ -c $< -o main.o
上面示例中,$^
指的是 main.o math.o
, $@
指的是 main
, $<
指 main.cpp
2.6 目标特定变量¶
- 语法:
pattern ... : variable-assignment
- 在目标依赖里进行变量的定义,这里定义的变量将会适用所有由这个目标展开的规则中去
## CFLAGS变量不仅适用prog,还适用以prog.o foo.o bar.o为目标规则中,也适用他们依赖的目标的规则中
prog : CFLAGS = -g
prog : prog.o foo.o bar.o
2.7 模式特定变量¶
- 语法:
pattern ... : variable-assignment
- 类似与目标特定变量,此用来模式匹配目标。
如:
%.o : CFLAGS = -O
将会匹配所有.O
后缀的目标,如果存在多个模式特点变量,优先匹配匹配限定更多的那个,如下:
%.o: %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
lib/%.o: CFLAGS := -fPIC -g
%.o: CFLAGS := -g
all: foo.o lib/bar.o
上面如果目标是 lib/1.o
,则优先使用 lib/%.o: CFLAGS := -fPIC -g
这个匹配。
2.8 抑制目标变量的继承¶
在目标特定变量、模式特定变量中定义的变量是可以被依赖的目标使用的,如果不想要这样,可以是 private
抑制变量的继承。如:
EXTRA_CFLAGS =
prog: private EXTRA_CFLAGS = -L/usr/local/lib
prog: a.o b.o
上面的 a.o
、b.o
将不会继承 EXTRA_CFLAGS 的值。
2.9 模式变量¶
2.9.1 通配符%和*¶
%
和*
都是用来匹配多个字符的作用,但使用地方不同%
:通常在目标和依赖中成对出现,如%.o:%.c
, 此时假设有test.o
的目标被构建,则依赖自动扩展成test.c
*
:一般用于模糊匹配目录下文件,如files=*.c
,表示变量files
等于当前所有以.c
结尾的文件;但当如果目录下,没有一个以.c
结尾的文件时,就会扩展成files=*c
,所有一般还是使用wildcard
函数来取代
2.9.2 %示例¶
- 示例
.PHONY:targ1
targ1:1.o 2.o
@echo
%.o:%.c
@echo 【%.o:%.c】 目标=$@ 依赖=$^
touch $@
%.c:
@echo 【%.c:】 目标=$@ 依赖=$^
touch $@
- 结果
$ make
【%.c:】 目标=1.c 依赖=
touch 1.c
【%.o:%.c】 目标=1.o 依赖=1.c
touch 1.o
【%.c:】 目标=2.c 依赖=
touch 2.c
【%.o:%.c】 目标=2.o 依赖=2.c
touch 2.o
rm 2.c 1.c
2.9.3 *示例¶
- 示例 1:当下面示例中存在任务一个以
.c
结尾的文件(如 test.c)时
.PHONY:targ1
targ1:*.c
@echo 目标=$@ 依赖=$^
- 执行 make,结果如下,
*.c
扩展成了test.c
文件
$ make
目标=targ1 依赖=test.c
- 示例 2:当下面示例中存在任务没有任何以
.c
结尾的文件时
.PHONY:targ1
targ1:*.c
@echo 目标=$@ 依赖=$^
- 执行 make,结果如下,
*.c
没有被扩展
$ ls
makefile
$ make
echo *.c
*.c
目标=targ1 依赖=*.c
3 内置变量¶
3.1 常用程序变量名¶
make 变量 | 实际值 | 说明 |
---|---|---|
$(RM) |
rm -f | 删除文件 |
$(SHELL) |
/bin/bash |
|
$(AR) |
ar | 用于生成静态库的程序 |
$(AS) |
as | 汇编工具 |
$(MAKE) |
make | |
$(CC) |
cc | c 编译器 |
$(CXX) |
g++ | cpp 编译器 |
$(CPP) |
$(CC) -E |
c 预处理命令 |
$(INSTALL) |
install | 复制文件并设置属性的工具 |
$(LD) |
ld | GNU 链接器 |
$(LDCONFIG) |
ldconfig | 刷新动态链接库缓存 |
$(BISON) |
bison | |
$(FLEX) |
flex | |
$(LEX) |
lex | 用于将 Lex 语法转换为源代码的程序 |
$(MAKEINFO) |
makeinfo | 将 Texinfo 源文件转换为 Info 文件的程序 |
$(RANLIB) |
ranlib | |
$(TEXI2DVI) |
texi2dvi | |
$(YACC) |
yacc | 用于将 Yacc 语法转换为源代码的程序 |
$(LINT) | lint | 用于在源代码上运行 lint 的程序 |
3.2 常用的编译选项¶
make 变量 | 说明 | 默认值 |
---|---|---|
ARFLAGS | ar 工具参数 | rv |
ASFLAGS | as 工具参数 | 空 |
CFLAGS | c 编译器选项 | 空 |
CXXFLAGS | cpp 编译器选项 | 空 |
LDFLAGS | 用于链接库的参数,如 -lfoo |
|
LDFLAGS | ld 参数 | 空 |
3.3 其它变量¶
3.3.1 SHELL¶
SHELL
一般是 /bin/sh
all:
@echo top makefile
$(info SHELL:$(SHELL))
SHELL=/bin/bash
$(info SHELL:$(SHELL))
输出结果:
[shw@rocky make]$ make
SHELL:/bin/sh
SHELL:/bin/bash
top makefile
3.3.2 MAKEFILE_LIST¶
MAKEFILE_LIST
: 这个变量会按顺序保存所有执行过的 makefile 文件名的绝对路径,如下输出结果 2 个 makefile 路径 makefile common/makefile
:
##### makefile
include common/makefile
all:
@echo mian makefile
@echo MAKEFILE_LIST列表:$(MAKEFILE_LIST)
##### common/makefile
test:
@echo sub makefile
输出结果:
[shw@rocky make]$ make test all
sub makefile
mian makefile
MAKEFILE_LIST列表:makefile common/makefile
3.3.3 .RECIPEPREFIX¶
命令行的首字符默认是 tab 字符,通过修改 .RECIPEPREFIX
就能改变命令行首字符。比如如,用 >
字符替换 tab 字符 :
.RECIPEPREFIX = >
all:
> @echo Hello, world
.RCEPPEREFIX 的值可以多次更改;一旦设置,它将对解析的所有规则保持有效,直到修改。
3.3.4 .INCLUDE_DIRS¶
.INCLUDE_DIRS
保存了 include 指定搜索 makefile 文件的位置,这个变量能通过 make -I DIRECTORY, --include-dir=DIRECTORY
设置,如:
项目结构:
[shw@rocky make]$ tree
.
├── common
│ └── sub.mk
└── makefile
makefile 如下
include sub.mk
all:
@echo top makefile
$(info .INCLUDE_DIRS:$(.INCLUDE_DIRS))
输出结果:
[shw@rocky make]$ make -I ./common
.INCLUDE_DIRS:common /usr/include /usr/local/include /usr/include
sub makefile
3.3.5 .DEFAULT_GOAL¶
.DEFAULT_GOAL
表示默认的 target 是哪一个,这个值保存的是第一个 target, include 的 makefile 也参与这个规则。即使 make 是指定了 target,这个变量也不会被影响。
test:
@echo test target
all:
@echo top makefile
$(info .DEFAULT_GOAL:$(.DEFAULT_GOAL))
输出结果:
[shw@rocky make]$ make all
.DEFAULT_GOAL:test
top makefile
3.3.6 .FEATURES¶
.FEATURES
变量能获取此版本的 make 支持的特殊功能列表。可能的值包括但不限于:
- archives
: Supports ar (archive) files using special file name syntax.
- check-symlink
: Supports the -L (--check-symlink-times) flag.
- else-if
: Supports “else if” non-nested conditionals.
- jobserver
: Supports “job server” enhanced parallel builds
- oneshell
: Supports the .ONESHELL special target
- order-only
: Supports order-only prerequisites
- second-expansion
: Supports secondary expansion of prerequisite lists.
- shortest-stem
: Uses the “shortest stem” method of choosing which pattern, of multiple applicable options, will be used.
- target-specific
: Supports target-specific and pattern-specific variable assignments.
- undefine
: Supports the undefine directive
- guile
: Has GNU Guile available as an embedded extension language
- load
: Supports dynamically loadable objects for creating custom exten
sions
3.3.7 .EXTRA_PREREQS¶
.EXTRA_PREREQS
可以给单个目标或者全局设置依赖,使用场景:假设 gcc 被更新了,我们也希望我们的目标能够重新构建,这时可以这样:
myprog: myprog.o file1.o file2.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
myprog: .EXTRA_PREREQS = $(CC)