Makefile编写
1. make和Makefile的介绍
1.1 make工具
利用make
工具可以自动完成编译工作。这些工作包括:
- 如果仅仅修改了某几个源文件,则只重新编译这几个源文件;
- 如果某个头文件被修改,则重新编译所有包含该头文件的源文件。
利用这种自动编译可大大简化开发工作,避免不必要的重新编译。
1.2 Makefile
make
工具通过一个称为Makefile
的文件来完成并自动维护编译工作。Makefile
文件描述了整个工程的编译、链接等规则。
2. Makefile基本规则
TARGET ...:DEPENDENCIES ...
COMMAND
...
- 目标(TARGET)程序产生的文件,如可执行文件和目标文件;目标也可以是要执行的动作,如
clean
,也称伪目标。 - 依赖(DEPENDENCIES)是用来产生目标的输入文件列表,一个目标通常依赖于多个文件。
- 命令(COMMAND)是
make
执行的动作(命令是shell命令或者是可在shell下执行的程序)。注意:每个命令行的起始字符必须为TAB
字符。 - 如果
DEPENDENCIES
中有一个或多个文件更新的话,COMMAND
就要执行,这就是Makefile
最核心的内容。
接下来就根据这个Makefile
基本规则来编写一个最基本的Makefile
文件
.PHONY:clean
main:main.o sub.o add.o print.o
gcc -Wall -g main.o add.o sub.o print.o -o main
main.o:main.c
gcc -Wall -g -c main.c -o main.o
add.o:add.c add.h
gcc -Wall -g -c add.c -o add.o
sub.o:sub.c sub.h
gcc -Wall -g -c sub.c -o sub.o
print.o:print.c print.h
gcc -Wall -g -c print.c -o print.o
clean:
rm -f *.o main
我们可以看到,main
是我们最终想要生成的目标文件,它依赖main.o sub.o add.o print.o
这四个.o
文件。因此要执行gcc -Wall -g main.o add.o sub.o print.o -o main
命令来生成目标文件,但是当前没有这些.o
文件,因此就要先生成这些.o
文件。我们写了四条xxx.o:xxx.c
然后执行gcc -Wall -g -c xxx.c -o xxx.o
,这些语句就会生成目标文件的依赖项。
clean
是一个伪目标文件,因为它没有依赖项。我们只是想通过make clean
来将.o
文件删除,但是我们通常要指定.PHONY:clean
这条语句,用来显式的指定clean
是伪目标,来防止当前目录下有一个同名的clean
文件。这样,一个简单呢的Makefile
文件就写好了。
3. Makefile自动化变量
虽然像上述那样可以完成编译,但是明显非常麻烦,接下来介绍Makefile
的自动化变量。
选项名 | 作用 |
---|---|
$@ | 规则的目标文件名 |
$< | 规则的第一个依赖文件名 |
$^ | 规则的所有依赖文件列表 |
我们使用这些自动化变量来尝试从写刚才的Makefile
.PHONY:clean
OBJ=main.o sub.o add.o print.o
main:$(OBJ)
gcc -Wall -g $^ -o $@
main.o:main.c
gcc -Wall -g -c $< -o $@
add.o:add.c add.h
gcc -Wall -g -c $< -o $@
sub.o:sub.c sub.h
gcc -Wall -g -c $< -o $@
print.o:print.c print.h
gcc -Wall -g -c $< -o $@
clean:
rm -f *.o main
我们定义了一个变量叫OBJ
,他是我们的依赖项列表。然后使用自动化变量来代替对应的文件,如上所示。
但是,我们这些.c
文件都要生成.o
文件,这样写也非常麻烦,我们介绍另一些规则。
- 模式规则
%.o:%.c
- 后缀规则
.c:.o
我们来使用这两种规则:
.PHONY:clean
CC = gcc
CFLAGS = -Wall -g
OBJ = main.o sub.o add.o print.o
main:$(OBJ)
$(CC) $(CFLAGS) $^ -o $@
#%.o:%.c
.c.o:
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f *.o main
使用这两个规则,就会将所有.c
文件生成同名的.o
文件,这样,Makefile
就更加简洁。
4. make常用的内嵌函数
- 函数调用
$(function arguments)
- $(wildcard PATTERN)
- 当前目录写的匹配模式的文件
- 例如:src=$(wildcard *.c)
- $(patsubst PATTERN,REPLACEMENT,TEXT)
- 模式替换函数
- 例如:$(patsubst %.c, %.o, \$src)
- 等价于$(src:.c=.o)
- shell函数
- 执行shell命令
- 例如:$(shell ls -d */)