Makefile 是一种用于管理和自动化软件编译过程的文本文件。它包含了一系列规则,这些规则描述了如何根据源代码文件生成可执行文件或者其他目标文件。Makefile 的核心概念是规则和依赖关系,规则定义了如何生成一个或多个目标文件,而依赖关系则指定了生成目标文件所需要的源文件或其他依赖文件。
要是用 Makefile首先需要在终端中进行工具包的安装

sudo apt install -y build-essential

1、Makefile核心

Makefile 的核心是规则: 当“目标文件”不存在或者某个“依赖文件”比“目标文件”时间更新,则执行“命令”

目标:依赖1 依赖2
	命令

2、Makefile基本使用方式

# Makefile内容通常由以下3部分组成
# <目标名称>:<前置依赖>
#	\t<需要执行的命令>

# 放在第一个的是默认目标
# 目标是编译出main文件	依赖hello.o和main.o
# 编译的命令是gcc hello.o main.o -o main
main:hello.o main.o
	gcc hello.o main.o -o main

# 目标是main.o 依赖main.c和hello.h
# 编译的命令是gcc -c main.c (-o main.o)
main.o:main.c hello.h
	gcc -c main.c

# 目标是hello.c 依赖hello.c和hello.h
# 编译的命令是gcc -c hello.c
hello.o:hello.c hello.h
	gcc -c hello.c

clean:
	rm main hello.o main.o

在终端输入 make命令,make 会根据依赖关系进行执行
输入 make clean 则会调用 clean:后的内容
在这里插入图片描述

  • 根据规则分析:
    (1)目标文件是 main,发现此时依赖 hello.o 不存在,因此往下找 hello.o 作为目标的那一行
    (2)目标文件是 hello.o,并且目录中不存在,所以执行命令生成 hello.o
    (3)hello.o 有了,回到第一行,还需要 main.o,也不存在,参考 hello.o 继续生成 main.o
    (4)两个依赖都有了,可以执行生成 main 的命令了

3、引入变量

# 定义变量(换行使用'\'分隔)
objects := hello.o main.o
# $(objects)可以直接替换掉hello.o和main.o
# 编译的命令是gcc hello.o main.o -o main
main:$(objects)
	gcc $(objects) -o main

clean:
	rm main $(objects)

4、通配符

main:hello.o main.o
	gcc -o $@ $^
	
%.o:%.c
	gcc -c -o $@ $<
	
# `%.o`:所有 `.o` 文件
# `%.c`:匹配同名 `.c`
# `$@` = 目标文件
# `$<` = 第一个依赖
# `$^` = 所有依赖

hello.o:hello.h
# 单独声明一个依赖

5、自动推导

Makefile 对部分命令可以省略,会自动判断进行推导。
但是!自动推导只能监控 .c 文件,对于 .h 文件无法监控。即当一次 make 完后,如果对 .c 文件进行了修改,makefile 会重新执行,但是如果修改的是 .h 文件,则显示“已是最新”,不会重新执行编译!

# 定义变量(换行使用'\')
objects := hello.o main.o

# 放在第一个的是默认目标(必须要写)
main:$(objects)
	gcc $(objects) -o main
# 中间过程可以不写,自动推导
main.o:hello.h
hello.c:hello.h
clean:
	rm main $(objects)

在这里插入图片描述

6、引入伪目标

6.1 伪目标

伪目标并不代表实际的文件名,更多的是行为或动作的标识符。伪目标并不生成具体文件

6.2 . PHONY目标

(1). PHONY 是 Makefile 中一个特殊的目标,用于声明其他目标是伪目标
(2)语法:. PHONY:<伪目标名称>

# 声明伪目标
.PHONY:clean
# clean默认就是伪目标
clean:
	rm main $(objects)

如果工作目录中有一个 clean 文件,但是 Makefile 中 clean 我们是一个任务,并不是表示一个文件,而是要调用这个 make clean 删除一些文件,此时如果不显示声明 clean 为伪目标,Makefile 会认为这个 clean 是个目标文件,从而导致错误:“clean已是最新”,加上显示声明后,make clean 被判断为任务,进行文件的删除

7、忽略错误

只需要在命令前加‘-’就能实现错误的忽略

# 不忽略错误
clean:
	rm main $(objects)
# 忽略错误
clean:
	-rm main $(objects)

在这里插入图片描述

8、目标名和命令输出文件名的关系

main:$(objects)
	gcc $(objects) -o main

可以看到以上代码中目标名称和任务命令中都有 main,但是实际上决定输出文件名的是任务命令中的 main,因为 Makefile 的底层是调用 gcc 指令。例如:如果将命令改成 gcc $(objects) -o main666 那么最后输出的文件名则是 main666。
但是,一般不会将这两个设置为不同名称,因为目标名称决定了 Makefile 追踪的那个文件名,如果两个名称不一样,当多次输入 make 命令后,Makefile 将会重复输出 main123,因为目录中始终找不到 main这个文件

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐