自动化构建工具make与Makefile用法示例详解

 更新时间:2026年05月03日 11:14:29   作者:凤年徐  
make是一个命令工具,是一个解释makefile在指令的命令工具,大多数的IDE都存在这个命令, makefile成为一种在工程方面的编译方法,这篇文章主要介绍了自动化构建工具make与Makefile用法的相关资料,需要的朋友可以参考下

1. 什么是 make / Makefile?

make 是一个自动化构建工具,它根据一个叫做 Makefile 的文件中的规则,自动编译和链接程序。更本质一点说,make是一个命令,makefile是一个文件
Makefile 定义了文件之间的依赖关系以及如何生成目标文件。

注意:Makefile 文件名首字母可以大写也可以小写,但通常使用 Makefilemakefile

2. Makefile 的基本结构

依赖关系与依赖方法

一个典型的规则如下:

target: dependencies
    recipe
  • 第一行target 是要生成的目标文件,dependencies 是生成该目标所依赖的文件。
  • 第二行recipe 是生成目标的命令(必须以 Tab 键开头)。

示例:

myproc:myproc.c
    gcc -o myproc myproc.c

  • myproc 是目标文件,依赖 myproc.c
  • 依赖方法:gcc -o myproc myproc.c

make 的执行规则

  • make 命令默认扫描当前目录下的 Makefile,并执行 第一个 目标。
  • 如果依赖文件的时间戳比目标文件新(即内容被修改过),则重新生成目标;否则跳过。
  • 这样设计可以避免重复编译未修改的代码,提高构建效率。

3. 如何判断文件是否被修改?

之前说过,文件=内容+属性

文件的三个时间戳(stat 命令)

在 Linux 中,每个文件都有三个时间戳:

时间戳含义
Access最近一次访问时间(读文件)
Modify最近一次内容修改时间
Change最近一次属性修改时间

注意:

  • 修改文件内容时,Modify 和 Change 都会更新(因为文件大小等属性变了)。
  • 单独修改属性(如 chmod)只会更新 Change。
  • Access 时间不会每次都更新(为了减少磁盘 I/O),通常访问多次后才刷新一次。

make 的判断依据

make 只根据 Modify 时间来判断文件内容是否发生了更改

如果依赖文件的 Modify 时间晚于目标文件,则重新生成。

使用 touch 修改时间

touch 命令除了可以创建空文件,还可以将所有时间戳更新为当前时间:

touch filename   # 将 filename 的 Access、Modify、Change 都改为当前时间

利用这个特性,可以强制让 make 认为文件被修改过,从而总是执行某个目标。

touch可以统一更改时间到当前时刻

为什么讲这些呢?

因为这些是关键字PHONY的原理

PHONY可以使程序可以总是被执行,下图中的clean就是如此,原理就是通过touch修改时间

所以我们使用make clean的时候可以总是被执行

如果改成下图这样,make也可以总是被执行,但为了节省编译时间,通常不会这样做

4. 伪目标(.PHONY)

为什么需要伪目标?

有时候我们想执行一些不生成具体文件的操作(例如 clean 删除中间文件)。但 clean 本身不是一个真实的文件,如果恰好当前目录下有一个名为 clean 的文件,make clean 就会认为目标已经存在且无依赖,从而跳过执行。

使用 .PHONY 声明伪目标

.PHONY: clean
clean:
    rm -f *.o hello
  • .PHONY 告诉 make:clean 不是一个真实文件,无论是否存在,都执行它的命令。
  • 伪目标的原理本质上是 make 强制把它的依赖时间视为“总是比目标新”,从而总是执行。

能否让普通目标也总是执行?

可以,但不推荐。例如:

hello: hello.c
    gcc hello.c -o hello
    touch hello   # 更新 hello 的时间戳,这样下次 make 时会认为 hello 比依赖新,从而不编译

这样会导致每次 make 都重新编译,失去了增量编译的优势。因此,一般只对 clean 等辅助目标使用 .PHONY

5. Makefile 的推导规则(自动推导)

拆分写法(不常用,仅用于理解)

上述的命令可以拆分成下图(一般不这样写,为了讲解原理而拆分)

makefile会从上向下扫描,没有就入栈,有就出栈执行

在实际开发中,我们一般这样写

其中$(BIN) 和 (SRC)替换成(SRC) 替换成(SRC)替换成@和$^

  • $@ 表示目标文件。
  • $^ 表示所有依赖文件。

如果不想回显命令,可以在前边加上@

如果想看起来直观一点,可以在命令后输出一行,指定内容

make 会从上向下扫描,发现需要 hello.o,则先去执行生成 hello.o 的规则,再返回执行 hello 的规则。

简化写法(常用)

实际开发中,我们通常会使用变量和自动化变量来简化:

BIN = hello
SRC = hello.c

$(BIN): $(SRC)
    gcc -o $@ $^

隐藏命令回显

在命令前加 @ 可以阻止 make 输出该命令本身:

$(BIN): $(SRC)
    @gcc $^ -o $@
    @echo "编译完成"

处理多个源文件

  • %.o: %.c 是一个模式规则,表示所有 .o 文件都依赖对应的 .c 文件。
  • $< 表示第一个依赖文件(即对应的 .c 文件)。

6. Makefile 的终极形态(通用模板)

说明:

  • wildcard 函数:展开当前目录下所有 .c 文件。
  • SRC:.c=.o 是变量替换语法,将所有 .c 后缀替换为 .o
  • 这个模板可以自动适应任意数量的 .c 文件,无需手动列出。

SRC=$(shell ls *.c)
SRC=$(wildcard *.c) #两种方式都可以 显示当前目录下的所有.c文件
OBJ=$(SRC:.c=.o) #把所有SRC内部的.c文件替换成.o文件

总结

概念说明
依赖关系目标文件依赖哪些源文件或中间文件
依赖方法生成目标的具体命令,前面必须有一个 Tab
时间戳make 根据文件的 Modify 时间判断是否需要重新编译
伪目标.PHONY 声明,总是执行其命令(如 clean
自动化变量$@(目标)、$^(所有依赖)、$<(第一个依赖)
模式规则%.o: %.c 表示所有 .o 依赖同名 .c
函数wildcardshell 等用于动态获取文件列表

掌握这些内容,你就可以编写灵活、高效的 Makefile,实现项目的自动化构建。

新编译 |
| 伪目标 | 用 .PHONY 声明,总是执行其命令(如 clean) |
| 自动化变量 | $@(目标)、$^(所有依赖)、$<(第一个依赖) |
| 模式规则 | %.o: %.c 表示所有 .o 依赖同名 .c |
| 函数 | wildcardshell 等用于动态获取文件列表 |

掌握这些内容,你就可以编写灵活、高效的 Makefile,实现项目的自动化构建。

到此这篇关于自动化构建工具make与Makefile用法示例详解的文章就介绍到这了,更多相关自动化构建工具make与Makefile内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 每天学一个 Linux 命令之more命令

    每天学一个 Linux 命令之more命令

    more命令,功能类似 cat ,more会以一页一页的显示方便使用者逐页阅读,而最基本的指令就是按空白键(space)就往下一页显示,按 b 键就会往回(back)一页显示,而且还有搜寻字串的功能
    2016-12-12
  • 使用shell脚本判断文件后缀的方法实例

    使用shell脚本判断文件后缀的方法实例

    这篇文章主要给大家介绍了关于如何使用shell脚本判断文件后缀的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-03-03
  • shell脚本自动安装jdk的方法示例

    shell脚本自动安装jdk的方法示例

    这篇文章主要介绍了shell脚本自动安装jdk的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • Linux系统中掩耳盗铃的sudo配置

    Linux系统中掩耳盗铃的sudo配置

    这篇文章主要介绍了Linux系统中掩耳盗铃的sudo配置的相关资料,需要的朋友可以参考下
    2015-09-09
  • ps命令输出进程状态S+的含义解析

    ps命令输出进程状态S+的含义解析

    这篇文章主要介绍了ps命令输出进程状态S后面加号的含义,本文通过ps命令输出说明,感兴趣的朋友跟随小编一起看看吧
    2019-12-12
  • shell 判断语句脚本用法解析

    shell 判断语句脚本用法解析

    这篇文章主要为大家介绍了shell判断语句脚本用法解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • 查询上次Ubuntu重启时间的方法命令总结

    查询上次Ubuntu重启时间的方法命令总结

    在大多数情况下,Linux 系统的关机时间、重启日期和运行时长等调试信息在系统故障排错时会显得比较重要,本文将详细介绍多种方法来查询上次 Ubuntu 重启的时间,并解释每种方法的背后原理,需要的朋友可以参考下
    2024-05-05
  • Linux shell中的-d,-f,-e,-n的作用小结

    Linux shell中的-d,-f,-e,-n的作用小结

    本文主要介绍了Linux shell中的-d,-f,-e,-n的作用小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • Shell脚本实现自动发送邮件的例子

    Shell脚本实现自动发送邮件的例子

    这篇文章主要介绍了Shell脚本实现自动发送邮件的例子,使用.muttrc文件配合shell脚本实现,需要的朋友可以参考下
    2014-08-08
  • linux 下获取当前工作路径的实例

    linux 下获取当前工作路径的实例

    今天小编就为大家分享一篇linux 下获取当前工作路径的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-06-06

最新评论