Makefile详解

HarderHeng Lv5

一、Makefile是什么

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

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

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

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

二、Makefile基础

1、目标

  • makefile文件直接命名为makefile才能让make工具识别。
  • makefile的编写规则为目标+编写规则,在目标名后面加上就代表这是一个目标的条目
1
2
3
all:
@echo "HelloWorld"\
#目标名为all,在构建目标时执行echo命令,加上@后在命令行里就不会打印多余的内容

image-20240409213927459

  • 如果在同一个makefile中定义了多个目标,然后直接在命令行中执行make命令,就会执行makefile中的第一个目标。当然也可以自己指定要构建的目标。

    2、依赖

    依赖是包含在规则中的一部分,如果一个目标依赖于另一个目标,那么就要依次先构建依赖的关系目标,才能构建当前的目标。

    1
    2
    3
    4
    5
    all: test
    @echo "HelloWorld"
    test:
    @echo "test"
    #在构建目标all时,会先构建其先决条件test目标

    image-20240409214548703

    3、规则

    一条目标的条目其实也就是一个整个规则,由目标依赖命令组成。其中依赖必须在构建该目标之前就已经满足,这个依赖也可以是其他的目标,也就是会被先构建出来才会构建原本的目标。规则的命令需要能够生成出目标,才能被其他目标作为依赖。

三、Makefile的特性

1、不重复构建

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

1
2
3
4
5
6
7
8
9
10
#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"
1
2
3
4
5
6
//main.c
extern void helloworld();
int main(){
helloworld();
return 0;
}
1
2
3
4
5
//helloworld.c
#include<stdio.h>
void helloworld(){
printf("HelloWorld");
}

image-20240409222123641

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

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

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

2、假目标

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

不使用假目标的效果

image-20240409224219548

  • 假目标就是为了避免所要构建的目标和已经存在的文件重名的情况。
1
2
3
4
5
6
7
8
9
10
11
#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的构建被单纯的当成一个目标而并非是一个文件,并不会检查此时文件的存在性。

image-20240409224235265

3、变量

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

1
2
SRC = folder
$(SRC)

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

内置变量

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

  • $@:表示目标文件
  • $^:表示所有依赖的文件
  • $<:表示第一个依赖文件

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

变量赋值

这里有三种赋值方式。

  • = 这种赋值方式会在调用变量时进行变量的赋值计算
  • Title: Makefile详解
  • Author: HarderHeng
  • Created at : 2024-04-13 16:58:28
  • Updated at : 2024-12-23 15:24:58
  • Link: https://harderheng.life/2024/04/13/Makefile详解/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments