0


【Linux必备工具】自动化构建工具makefile的使用详解

文章手稿见文末~

引言

项目构建时遇到的各种挑战如文件编译顺序、库链接、依赖文件的管理等,在不同开发环境中会有不同的解决方案。

在 Visual Studio (VS) 环境中,这些问题往往被自动处理,运行直接 Ctrl + F5 就可以了,编译个项目真的轻轻松松。 那是因为 VS 帮你自动维护了对应的项目结构!

那如果需要手动实现呢:多文件 我们先编译哪一个程序?链接需要哪些库?整个项目结构,该如何维护......在 Linux 环境中,我们需要更手动、细致地管理这些方面。为了解决这个问题,Linux 提供了自动化构建工具 Makefile。

Makefile 简介

Makefile 是 Linux 下用于管理文件依赖和编译顺序的一个重要工具。它用于定义项目中的各个源文件如何编译链接,可以极大地提高开发效率。

Makefile 文件中定义了一系列规则,指定文件编译顺序、文件依赖关系及各文件的编译方法。**

make

命令**是一个解释 Makefile 文件的命令工具,可以完成项目的自动化构建。

依赖关系与依赖方法

在一个大项目中例如一不小心写反gcc的执行,可执行程序就覆盖掉了原文件,最后导致你的源代码都没了……由此可见,在命令行操作时如果出现误操作,就会翻车。正是因为这些悲剧的存在,使得 Makefile 的光芒愈发温暖!

我们先做一些准备工作,touch makefile ,然后vim 输入以下指令

可以将依赖关系和依赖方法类比为生活中的要钱例子:打电话告诉爸爸"我是你儿子"表示依赖关系,而要求给你打钱表明了依赖方法。只有同时满足依赖关系和依赖方法,才能成功达到目的,即完成编译和链接。

在 Makefile 中,最核心的概念是依赖关系和依赖方法。依赖关系用于指定某个目标文件依赖哪些源文件,当这些源文件发生变化时,需要重新生成目标文件。依赖方法则是生成目标文件所执行的具体命令。

效果:

以后我们在 Linux 下编译代码就不需要敲 gcc 命令了,直接 make 就可以了,尤其是在大项目中会特别的方便

make运行规则

❓ 思考:为什么 make 的时候它总是执行第一个呢?

makefile 在形成文件时会自顶而下扫描,默认只会形式第一个目标文件,执行该依赖关系的依赖方法。

我们这里有两个目标文件,一个是 mytest 一个是 clean,凭什么我 make 执行的是 mytest 而不是 clean?答案很简单,就凭 mytest 是在前面写的!

如果我们把它们两的顺序换一下:

因为上下位置的调换,修改了make的默认操作

依赖关系示例

假设我们有以下文件依赖关系:

hello: hello.o
hello.o: hello.s
hello.s: hello.i
hello.i: hello.c

依赖方法

使用

gcc

命令编译不同中间文件:

hello: hello.o
    gcc hello.o -o hello

hello.o: hello.s
    gcc -c hello.s -o hello.o

hello.s: hello.i
    gcc -S hello.i -o hello.s

hello.i: hello.c
    gcc -E hello.c -o hello.i

在上述例子中,

hello

是最终目标文件,它依赖于目标文件

hello.o

,而后者又进一步依赖于

hello.s

,如此递归下去直到源文件

hello.c

Makefile 工作原理

  1. make 命令查找名为 Makefilemakefile 的文件。
  2. 读取文件并找到第一个目标文件,在本例中是 hello
  3. 如果 hello 不存在,或其依赖文件中任何一个文件比 hello 更新,则生成 hello 文件。
  4. 递归检查每个依赖文件,按顺序进行必要的编译步骤。
  5. 如果出现错误,make 退出并报错。
  6. 如果依赖文件仍然不在,make 也将退出。

示例代码

这是一个简单的 C 代码示例和相应的 Makefile 文件:

// hello.c
#include <stdio.h>
int main() {
    printf("hello Makefile!\n");
    return 0;
}
# Makefile
hello: hello.o
    gcc hello.o -o hello

hello.o: hello.c
    gcc -c hello.c -o hello.o

.PHONY: clean
clean:
    rm -f hello.o hello

在这个示例中,

hello

目标文件依赖于

hello.o

文件,而

hello.o

则由

hello.c

编译生成。

clean

是一个伪目标,无论何时执行

make clean

clean

中的命令都会被执行,达到清理文件目的。

清理项目与伪目标

工程经常需要清理生成的中间文件和目标文件,Makefile 提供了方便的清理机制。通过定义伪目标,可以确保

make clean

总能执行对应的清理命令。

清理示例

代码:

.PHONY: clean
clean:
    rm -f hello.o hello

clean 没有依赖文件,也是存在依赖关系的,只不过这个 clean 没有依赖列表。

.PHONY

用于标记

clean

为伪目标,无论当前目录下是否有

clean

文件或目标,

make clean

命令都会执行。

效果:

.PHONY总是被执行

我们刚才看了 "总是不被执行" 的现象,我们试试给我们的 mytest 也用 ​{\color{Red} .PHONY},让它从默认的 "总是不被执行" 变成 "总是被执行" 看看

但为了提高效率,我们一般不建议这样

实际上是make一次,如果未发生改变就不会再执行了

详细解释如下:

我们打开文件修改,Access 应不应该改变呢?我们读取 Access 变不变?

要变的!但是现在不会变!因为访问文件的频率是最高的,Modify 和 Change 是不得不变的,不变的化文件就不对了。但是我们大多数情况修改文件属性和修改文件内容是很低频的事情,但打开文件是非常高平的事情,Linux 后期内核对 Access 进行了优化,将文件打开访问,打开时间不会变化,累计一段时间后他才会变化。如果不这样,打开文件这种高频率的事情,一旦更新 Access 时间,就要将数据刷新到磁盘上,这实际上一个很没效率的事情。

具体 Access 的调整策略取决于 Linux 的版本。

让我们再来回答一下最初的怎么做到的?

通过对比你的源文件和可执行程序的**更改时间 **(modify time) 识别的新旧。 根据原文件和可执行程序的最近修改时间,评估要不要重新生成。

文章手稿:

标签: 算法 linux 运维

本文转载自: https://blog.csdn.net/2301_80171004/article/details/139856443
版权归原作者 lvy¯ 所有, 如有侵权,请联系我们删除。

“【Linux必备工具】自动化构建工具makefile的使用详解”的评论:

还没有评论