【Linux】make命令 | makefile文件详解

[复制链接]
发表于 2026-10-3 22:52:35 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

每次改完一个 .c 文件,都要手动 gcc 一下、再删掉旧的可执行文件、再 gcc 一次——这种重复劳动其实可以彻底省掉。Linux 下的 make 命令配合 makefile 就是为了这件事而生的:只编译真正改过的部分,一条命令把整个工程构建出来。

一、make 与 makefile 先见个面

假设我们有一个 proc.c,新建一个名字叫 Makefile( makefile 也认,两个名字都可以 )的文件,写进几条规则,然后命令行里直接敲 make,就会生成一个名为 proc 的可执行文件。

到这一步确实比直接敲 gcc 还多了个文件,但往下学你会发现它用起来很省心。

二、依赖关系与依赖方法

先解释两个词:什么是依赖关系?什么是依赖方法?打个比方,你和你爹,这就是依赖关系;你跟你爹要钱,这就是依赖方法。所以必须先有依赖关系,之后才有依赖方法。

回到 makefile:形成 proc 可执行程序依赖 proc.c,两者缺一不可;但光有依赖还不够,还得写明这个程序是怎么被生成的,这就是依赖方法。

makefile 的本质,就是一堆依赖关系的集合。

三、清理项目与执行顺序

想清理构建产物,在 Makefile 里再加几句:

.PHONY: clear
clear:
    rm -f proc

然后执行 make clear 就能清理掉。

这里的 clear 目标右边没有依赖文件。makefile 是从上往下扫描的,第一行的目标名可以直接用 make 省略掉,所以 make proc 中的 proc 也能省略;反过来,如果想执行别的组规则,就得写 make 目标名。

一般建议把清理规则放在文件最后,避免它抢了第一个目标的位置。

四、在 makefile 里写其他 Linux 命令

# 在 makefile 里是注释符。依赖方法里写 gcc、写 rm,最后都会被 shell 执行。

但有个小问题:命令行会被回显出来,看起来很乱。要隐藏回显,用 @ 符号(@ 就是关闭命令回显)。加上之后输出干净很多,再配合 echo 就能打印自己的提示信息。

五、PHONY 关键字与时间判断

1. 为什么有时要重新编译,有时不用

两个要点:.PHONY 修饰的目标,对应的方法总是会执行;而普通目标会不会执行,取决于文件时间的比较。

源文件与可执行文件本质上都是文件,文件 = 内容 + 属性,可以用 stat 命令查看一个文件或文件系统的状态信息(Access、Modify、Change 三个时间戳)。

Access 是文件被访问的时间,因为调用频率太高、频繁修改反而影响效率,一般不做重点讨论。真正参与 make 判断的是 Modify 时间。

这里就解释清楚了之前那个现象:.PHONY 让依赖方法忽略时间对比,所以带 .PHONY 的目标每次都执行;而 clear 之所以不停执行,是因为它的方法是 rm -f,本身就不关心时间。

六、make 是怎么推导的

生成一个可执行文件要经过预编译、编译、汇编、链接几步,可以在 makefile 里把每一步都写出来。Makefile 执行顺序是从上到下,先找有没有 proc.o 这个依赖文件,没有就把它的依赖方法压栈,一路往下推导,直到找到现成的依赖文件,再逆向执行所有压过栈的方法。

一般我们不写那么长,而是利用默认规则让 make 自动推导,写法更短也更好读。

七、实用技巧:变量与通配符

一个项目不止一个 .c 文件。makefile 支持通配符和变量(不需要带类型),把源码列成变量,将来只改变量一处就够了,类似 C 语言里的宏替换:

SRC = main.c util.c net.c
OBJ = $(SRC:.c=.o)

app: $(OBJ)
    gcc -o $@ $(OBJ)

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

其中 $@ 代表目标名、$< 代表第一个依赖,这两个自动变量能让规则写得非常短。

八、一次生成多个可执行文件

再写一个 code.c 并改 makefile,你会发现 make 只生成了 proc 一个文件。想一次构建多个,需要引入一个并不对应产物的总目标 all:

all: proc code

proc: proc.o
    gcc -o proc proc.o

code: code.o
    gcc -o code code.o

all 目标没有源文件,执行时会继续向下推导依赖方法,最终同时生成 proc 和 code,并生成 all 这个"占位"目标。通常还会把 all 放在第一行。

九、小结

  • makefile = 依赖关系 + 依赖方法,第一行目标可以省略目标名直接 make。
  • @ 隐藏回显,# 是注释,.PHONY 让目标总是执行。
  • make 会递归推导依赖、压栈、最后逆向执行,只重编真正改过的部分。
  • 用变量和通配符管理源码列表,用 all 一次构建多个产物。

qidao123.com企服评测-应用市场 编辑提示

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表