linux shell

关注公众号 jb51net

关闭
首页 > 脚本专栏 > linux shell > 自动化构建工具make与Makefile

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

作者:凤年徐

make是一个命令工具,是一个解释makefile在指令的命令工具,大多数的IDE都存在这个命令, makefile成为一种在工程方面的编译方法,这篇文章主要介绍了自动化构建工具make与Makefile用法的相关资料,需要的朋友可以参考下

1. 什么是 make / Makefile?

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

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

2. Makefile 的基本结构

依赖关系与依赖方法

一个典型的规则如下:

target: dependencies
    recipe

示例:

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

make 的执行规则

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

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

可以,但不推荐。例如:

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 "编译完成"

处理多个源文件

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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文