太一的博客

一个程序学徒

makefile

make 工具

  • 利用 make 工具可以自动完成编译工作。这些工作包括:如果仅修改了某几个源文件,则只重新编译这几个源文件;如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。利用这种自动编译可大大简化开发工作,避免不必要的重新编译。
  • make 工具通过一个称为 Makefile 的文件来完成并自动维护编译工作。Makefile 文件描述了整个工程的编译、链接等规则。

什么是Makefile

可执行程序的产生过程

配置环境(系统环境)==> 确定标准库和头文件的位置 ==> 确定依赖关系(源代码之间编译的依赖关系)==> 头文件预编译 ==> 预处理 ==> 编译 ==> 链接 ==> 安装 ==> 和操作系统建立联系 ==> 生成安装包

Makefile 是什么

当依赖关系复杂的时候,make 命令工具诞生了,而 Makefile 文件正是为 make 工具所使用的

Makefile 做了什么

它描述了整个工程所有文件的编译顺序、编译规则

Makefile

基本规则

1
2
3
TARGET ... : DEPENDENCIES ...
COMMAND
...
  • 目标( TARGET )程序产生的文件,如可执行文件和目标文件;目标也可以是要执行的动作,如 clean,也称为伪目标
  • 依赖( DEPENDENCIES )是用来产生目标的输入文件列表,一个目标通常依赖于多个文件
  • 命令( COMMAND )是 make 执行的动作(命令是 shell 命令或是可在 shell 下执行的程序)。注意:每个命令行的起始字符必须为 TAB 字符
  • 如果 DEPENDENCIES 中有一个或多个文件更新的话,COMMAND 就要执行,这就是 Makefile 最核心的内容

伪目标

1
2
3
4
5
6
7
8
9
10
11
.PHONY:clean
main:main.o add.o sub.o
gcc -Wall -g main.o add.o sub.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
clean:
rm -f main main.o add.o sub.o

为什么要显式指定伪目标?

例如,如果当前文件夹下有clean,使用make clean就会:

image-20241003113736167

Makefile 中的变量

1
2
3
$@	规则的目标文件名
$< 规则的第一个依赖文件名
$^ 规则的所有依赖文件列表
1
2
3
4
5
6
7
8
9
10
11
12
.PHONY:clean
OBJECTS=main.o add.o sub.o
main:$(OBJECTS)
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 $@
clean:
rm -f main $(OBJECTS)

Makefile 编译多个可执行文件

  • 模式规则

    • %.o:%.c
  • 后缀规则

    • .c.o:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.PYHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN=01test 02test 03test
all:$(BIN)
%.o:%.c
$(CC) $(CFLAGS) -c $< -o $@
01test:01test.o
$(CC) $(CFLAGS) $^ -o $@
02test:02test.o
$(CC) $(CFLAGS) $^ -o $@
03test:03test.o
$(CC) $(CFLAGS) $^ -o $@
clean:
rm -f *.o $(BIN)

make常用内嵌函数

  • 函数调用
    • $(function arguments)
  • $(wildcard PATTERN)
    • 当前目录下匹配模式的文件
    • 例如:src=$(wildcard *.c)
  • $(patsubst PATTERN,REPLACEMENT,TEXT)
    • 模式替换函数
    • 例如:$(patsubst %.c,%.o,$src)
    • 等价于$(sr:.c=.o)
  • shell 函数
    • 执行shell命令
    • 例如:$(shell ls -d */)