语法
target ... : prerequisites ...
command
...
...
- target可以是一个object file(目标文件),也可以是一个执行文件,还可以是一个标签(label)。对于标签这种特性,在后续的“伪目标”章节中会有叙述。
- prerequisites就是,要生成那个target所需要的文件或是目标。
- command也就是make需要执行的命令。(任意的shell命令)
make工作
- 默认执行 make 命令时, GNU make在当前目录下依次搜索下面3个文件 "GNUmakefile", "makefile", "Makefile",
- 如果找到,它会找文件中的第一个目标文件(target),并把这个文件作为最终的目标文件。
- 如果target文件不存在,或是target所依赖的后面的 .o 文件的文件修改时间要比target这个文件新,那么,他就会执行后面所定义的命令来生成target这个文件。
- 如果target所依赖的文件也不存在,那么make会在当前文件中找依赖文件,如果找到则再根据那一个规则生成依赖文件。(这有点像一个堆栈的过程)
- 最终生成target文件
make 参数介绍
make 的参数有很多, 可以通过 make -h 去查看, 下面只介绍几个我认为比较有用的。
参数 | 含义 |
---|---|
--debug[=<options>] | 输出make的调试信息, options 可以是 a, b, v |
-j --jobs | 同时运行的命令的个数, 也就是多线程执行 Makefile |
-r --no-builtin-rules | 禁止使用任何隐含规则 |
-R --no-builtin-variabes | 禁止使用任何作用于变量上的隐含规则 |
-B --always-make | 假设所有目标都有更新, 即强制重编译 |
注意
- 所有的命令前要用tab分割
变量
定义变量(= or := )
- := 只能使用前面定义好的变量
- = 可以使用后面定义的变量
OBJS = programA.o programB.o
OBJS-ADD = $(OBJS) programC.o
# 或者
OBJS := programA.o programB.o
OBJS-ADD := $(OBJS) programC.o
使用变量 $()
变量追加值 +=
SRCS := programA.c programB.c programC.c
SRCS += programD.c
变量覆盖 override
目标变量
作用是使变量的作用域仅限于这个目标(target), 而不像之前例子中定义的变量, 对整个Makefile都有效.
语法:
<target ...> :: <variable-assignment>
-
<target ...> :: override <variable-assignment>
(override作用参见 变量覆盖的介绍)
# Makefile 内容
SRCS := programA.c programB.c programC.c
target1: TARGET1-SRCS := programD.c
target1:
@echo "SRCS: " $(SRCS)
@echo "SRCS: " $(TARGET1-SRCS)
target2:
@echo "SRCS: " $(SRCS)
@echo "SRCS: " $(TARGET1-SRCS)
# bash中执行make
$ make target1
SRCS: programA.c programB.c programC.c
SRCS: programD.c
$ make target2 <-- target2中显示不了 $(TARGET1-SRCS)
SRCS: programA.c programB.c programC.c
SRCS:
Makefile 命令前缀(@ or -)
Makefile 中书写shell命令时可以加2种前缀 @ 和 -, 或者不用前缀.
- 不用前缀 。输出执行的命令以及命令执行的结果, 出错的话停止执行
- 前缀 @ 只输出命令执行的结果, 出错的话停止执行
- 前缀 - 命令执行有错的话, 忽略错误, 继续执行
伪目标
伪目标并不是一个"目标(target)", 不像真正的目标那样会生成一个目标文件.
典型的伪目标是 Makefile 中用来清理编译过程中中间文件的 clean 伪目标, 一般格式如下:
.PHONY: clean <-- 这句没有也行, 但是最好加上
clean:
-rm -f *.o
引用其他的 Makefile
语法: include <filename> (filename 可以包含通配符和路径)
# Makefile 内容
all:
@echo "主 Makefile begin"
@make other-all
@echo "主 Makefile end"
include ./other/Makefile
# ./other/Makefile 内容
other-all:
@echo "other makefile begin"
@echo "other makefile end"
# bash中执行 make
$ ll
total 20K
-rw-r--r-- 1 wangyubin wangyubin 125 Sep 23 16:13 Makefile
-rw-r--r-- 1 wangyubin wangyubin 11K Sep 23 16:15 makefile.org <-- 这个文件不用管
drwxr-xr-x 2 wangyubin wangyubin 4.0K Sep 23 16:11 other
$ ll other/
total 4.0K
-rw-r--r-- 1 wangyubin wangyubin 71 Sep 23 16:11 Makefile
$ make
主 Makefile begin
make[1]: Entering directory `/path/to/test/makefile'
other makefile begin
other makefile end
make[1]: Leaving directory `/path/to/test/makefile'
主 Makefile end
Makefile 隐含规则
这里只列一个和编译C相关的.
编译C时,<n>.o 的目标会自动推导为 <n>.c
# Makefile 中
main : main.o
gcc -o main main.o
#会自动变为:
main : main.o
gcc -o main main.o
main.o: main.c <-- main.o 这个目标是隐含生成的
gcc -c main.c
自动变量
自动变量 | 含义 |
---|---|
$@ | 目标集合 |
$% | 当目标是函数库文件时, 表示其中的目标文件名 |
$< | 第一个依赖目标. 如果依赖目标是多个, 逐个表示依赖目标 |
$? | 比目标新的依赖目标的集合 |
$^ | 所有依赖目标的集合, 会去除重复的依赖目标 |
$+ | 所有依赖目标的集合, 不会去除重复的依赖目标 |
$* | 这个是GNU make特有的, 其它的make不一定支持 |
all
一种简写,可以让多个目标操作顺次执行
all: server.out client.out
objects = server.cpp
server.out : $(objects)
g++ -o server.out $(objects)
client.out : client.cpp
g++ -o client.out client.cpp
直接 make 或 make all 的话会执行 server.out 和client.out 的编译命令,后面不加参数的话,会把第一个目标作为默认的。