Skip to content

Makefile详解

· 9 min · C语言 / makefile / make / 学习笔记

一、Makefile是什么#

makefile定义了一些规则来制定项目如何进行编译。

makefile中包含了一系列的目标(Targets)和规则(Rules)。

目标通常是文件名,并且大概率是.o文件。紧跟着的生成这个文件的规则,通常是其源文件和编译的命令。编译的命令也可以是能够命令行执行的命令。

除了目标和规则,makefile也可以用来指定编译器的某些行为例如使用哪一个编译器或者编译器优化等级等等。

二、Makefile基础#

1、目标#

all:
@echo "HelloWorld"\
#目标名为all,在构建目标时执行echo命令,加上@后在命令行里就不会打印多余的内容

三、Makefile的特性#

1、不重复构建#

如果在makefile中以文件作为构建的目标,在执行make的时候就会将对应的文件构建出来,这些文件会一直存在,如果在下一次的构建中这些文件的源文件没有被修改,那么就不会重复构建这些文件。

#makefile
all: main.o helloworld.o
gcc -o main main.o helloworld.o #编译链接出main文件
@echo "Make all"
main.o: main.c #依赖源文件main.c
gcc -c main.c #编译出main.o
@echo "Make main.o"
helloworld.o: helloworld.c #依赖源文件helloworld.c
gcc -c helloworld.c #编译出helloworld.o
@echo "Make helloworld.o"
main.c
extern void helloworld();
int main(){
helloworld();
return 0;
}
helloworld.c
#include<stdio.h>
void helloworld(){
printf("HelloWorld");
}

执行了两次make,可以看到后一次make并没有构建目标main.o和helloworld.o,因为前一次make已经生成了这两个文件,并且在后一次make时会自动识别main.c和helloworld.c是否发生了更新时间的变化,也就是是否进行了更改,如果.c源文件没有被更改,make就认为要构建的目标main.o和helloworld.o也是最新的不需要进行重新构建。

那为什么all会被重新构建呢?

因为构建目标是all而不是gcc的目标main,main文件已经存在了但是目标all并不存在,关键在于要构建的目标是否存在。

2、假目标#

有时候我们构建出一个目标后,这个目标已经存在那么在进行重新构建时就不会执行任何该目标下的命令。但是有时我们需要该目标下除了构建这个目标的命令之外的命令,就需要想办法暂时屏蔽掉不重复构建的特性,这时候就可以用到假目标。

​ 不使用假目标的效果

#makefile
.PHONY: main.o
all: main.o helloworld.o
gcc -o main main.o helloworld.o #编译链接出main文件
@echo "Make all"
main.o: main.c #依赖源文件main.c
gcc -c main.c #编译出main.o
@echo "Make main.o"
helloworld.o: helloworld.c #依赖源文件helloworld.c
gcc -c helloworld.c #编译出helloworld.o
@echo "Make helloworld.o"

使用假目标后,可以进行同一目标的重复构建,此时main.o的构建被单纯的当成一个目标而并非是一个文件,并不会检查此时文件的存在性。

3、变量#

makefile中的变量有点像c语言中的宏定义,只进行字符串的替换。

SRC = folder
$(SRC)

直接定义变量,然后使用变量时就直接$( )进行引用。

一些常用的能简化Makefile编写的自定义变量:

预定义变量#

在make中有一些预定义变量,除了作为自己可以直接使用的变量,有的地方的隐式规则也可能会调用这些预定义变量。

一般优化等级、调试等等的选项都可以写在上述的两种FLAGS中。

自动变量#

对一条规则来说,需要有目标和依赖。

这三个内置变量在一条规则内使用则可以直接代表这些意义。

main: main.o test.o
$(CC) $^ -o $@

上面的例子就是说用所有的依赖文件作为编译器参数,来生成目标文件main。

变量赋值#

这里有三种赋值方式。

通配符#

make支持shell中的通配符。

4、隐式规则#

隐晦规则会使得make进行自动推导。

要使用一个.o文件时,如果没有定义生成.o文件的规则,则自动寻找这个.o文件对应的.c文件,进行自动的生成。

自动推导时,就会使用预定义的变量。

5、模式匹配#

模式匹配常和通配符一起使用,表示一系列的规则,来自动化的包含文件或者生成文件。

模式规则#

%.o: %.c
gcc -c $< -o $@

上述的规则用来匹配一个.o和.c文件,对每一个需要用到的.o文件都适用这个模式,根据下面的命令进行生成。

Wildcard关键字#

objects:= $(wildcard *.o)

上述的赋值语句使用了wildcard关键字,用来展开后面的通配符。

6、文件搜寻#

make执行命令时默认在当前的目录下工作,如果要在其他的目录中寻找文件,则