Makefile文件编写

语法

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[=] 输出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都有效.

语法:

  • ::
  • :: override (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 可以包含通配符和路径)

# 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时,.o 的目标会自动推导为 .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 的编译命令,后面不加参数的话,会把第一个目标作为默认的。

你可能感兴趣的:(Makefile文件编写)