Linux笔记---Makefile的简单用法

1. 什么是Makefile

Makefile 是一种用于自动化构建和管理项目的工具,特别是在软件开发中非常常见。

它包含了一系列规则(rules)和指令,描述了如何编译和链接源代码文件,以及生成最终的可执行文件或库文件。

简单来说,在系统中存在一个叫做make的命令,该命令被使用之后,会在当前目录下寻找一个叫做makefile/Makefile的文件,依据其内定义的规则进行项目的自动化构建。

当我们的项目由多个文件构成时,Makefile能够极大地简化我们构建程序的过程。

Makefile 的优点

自动化构建:通过 Makefile 可以自动化执行编译、链接等构建任务,减少手动操作。

增量构建:Makefile 可以根据文件的时间戳来实现增量构建,避免不必要的重复构建过程。

可移植性:Makefile 是跨平台的构建工具,可以在不同的操作系统上使用


2. Makefile的基本知识和基本用法


2.1 目标,依赖关系和命令

Makefile 的基本结构包括目标、依赖关系和命令。

目标是指要构建的文件或动作,依赖关系描述了生成目标所需的前置条件,而命令则是实际执行的操作,通常是编译源文件、链接目标文件或执行其他操作。

例如,我们需要生成一个test.exe(在Linux下可不带后缀)的可执行程序,而编译出test.exe依赖于其源文件test1.c,test2.c,test3.c...等,则可用下面的语句表述:

复制代码
目标:目标依赖的文件
    命令
    ...

注意:命令前有且仅能有 "一个TAB" 键,不可以手动敲4个空格。

保存退出,输入make命令:

可以看到,我们再输入make命令并回车之后,自动执行了我们预设的命令,并编译生成了可执行程序test。

如果不希望被自动执行的命令回显到屏幕上,我们可以在命令前加上 "@" :


2.2 伪目标

在一个Makefile文件中可以有多个目标,默认会执行第一个目标,也可在make后紧跟要执行的目标,以指定执行某个目标:

上面提到过,目标也可以是动作,这时常常不生成文件,我们叫这种目标为伪目标。

例如,我们有一个目标(clean)的作用是清除生成的可执行程序以重新生成:


2.3 .PHONY

相信看完上面一小节之后,大家会都很好奇.PHONY是什么。其实,被.PHONY修饰的目标就是始终会执行的目标。

这么说来,test和shishen不是始终会被执行的目标吗?我们尝试多次执行make,会发现:

第一次执行可以成功,然而之后再去执行却发现无法成功,而显示test已是最新。

这是因为test所依赖的文件没有发生更新,所以再次进行make没有任何意义,只会浪费系统资源。

所以,make仅仅提示test已是最新,而不去执行默认目标。

Makefile 通过检查目标文件及其依赖关系的时间戳,确定哪些文件需要重新构建。如果目标文件需要重新构建,Makefile 将按照规则中定义的命令来执行,以生成最终的目标文件。这种方式允许进行增量构建,即只重新构建发生变化的文件,从而提高构建效率。


2.4 自动构建工程的工作原理

Makefile自动构建工程的工作原理:如果某个目标的依赖文件不存在当前目录下,make就会尝试查找与依赖文件同名的目标并优先执行。

如果没有同名目标则会报错,即使在某个目标中存在生成所需文件的指令。

更准确地说,依赖关系列表中的元素默认为文件,当文件不存在时,认为其是同名目标,即使该目标不会生成所需文件,该目标也会被执行。

在下面这个例子中,我们让.c文件一步一步地生成可执行程序,而不是直接生成:

可以看到,即使我们没有指定,其余的三个目标也自动执行了,而且顺序是按照依赖关系的先后进行的。

可以猜想,make程序的内部应该会维护一个栈,用于存储需要执行,但依赖关系不满足的目标。


3. 简化Makefile的技巧语法


3.1 宏定义

当然,不是C语言的那个宏定义,但是二者十分相似,例如:

此时,"SRC" 就代表了所需源文件的集合,定义的符号需要放到 "$()" 中才能使用

在指令部分,也可用**"@" 代表目标,"^" 代表所依赖的文件**:

3.2 通配符

在Makefile中,通配符为 "%" ,假如要将所有.c文件先编译为对应的.o文件,再进行链接(也是最常用的方式):

3.3 相同后缀的集合

在源文件增多时,上面的Makefile需要在宏定义处增加对应的文件。

这未免太麻烦了,我们所使用的通配符也不能最大限度地发挥其作用。

而下面的写法可以解决这个问题:

4. 大多数情况下通用的Makefile

复制代码
BIN=code
CC=gcc
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
LFLAGS=-o
FLAGS=-c
RM=rm -f

$(BIN):$(OBJ)
	@echo "linking $^ to $@..."
	@$(CC) $(LFLAGS) $@ $^
%.o:%.c
	@echo "compling $< to $@..."
	@$(CC) $(FLAGS) $<

.PHONY:clean
clean:
	@echo "removing $(BIN)..."
	@$(RM) $(BIN) $(OBJ)
	@echo "Finish"
相关推荐
lulinhao11 分钟前
HCIA/HCIP基础知识笔记汇总
网络·笔记
小麦嵌入式25 分钟前
Linux驱动开发实战(十一):GPIO子系统深度解析与RGB LED驱动实践
linux·c语言·驱动开发·stm32·嵌入式硬件·物联网·ubuntu
刘若水27 分钟前
Linux: 进程信号初识
linux·运维·服务器
杉之41 分钟前
SpringBlade 数据库字段的自动填充
java·笔记·学习·spring·tomcat
阳小江1 小时前
Docker知识点
运维·docker·容器
WarPigs1 小时前
blender场景导入Unity的流程(个人总结)
笔记
只是橘色仍温柔2 小时前
xshell可以ssh连接,但vscode不行
运维·vscode·ssh
IT里的交易员2 小时前
【系统】换硬盘不换系统,使用WIN PE Ghost镜像给电脑无损扩容换硬盘
运维·电脑
共享家95273 小时前
深入剖析Linux常用命令,助力高效操作
linux·运维·服务器
大刘讲IT3 小时前
制造业数字化转型:流程改造先行还是系统固化数据?基于以MTO和MTS的投资回报分析
运维·经验分享·生活·产品经理·数据可视化