【Linux】自动化构建工具:make/Makefile

简介: 【Linux】自动化构建工具:make/Makefile

👻内容专栏: Linux操作系统基础

🐨本文概括: 工具使用的背景、理解make/makefile工具、探索工作原理(文件修改时间的对比)、.PHONY伪目标、特性等。

🐼本文作者: 阿四啊

🐸发布时间:2023.9.14

背景

  • make” 和 “Makefile” 是用于自动化构建和编译软件项目的工具和文件。它们通常用于编译源代码并生成可执行文件,库文件或其他项目构建目标。
  • 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。
  • makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
  • make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。

理解

make

📌"make" 是一个命令行,用于构建项目。它根据一个称为 “Makefile” 的文本文件中的规则来确定需要构建哪些文件以及如何构建它们。“make” 工具的基本语法如下:

make [目标]

⚠️注:其中 “目标” 是您要构建的项目中的一个特定目标,例如生成可执行文件或库。如果不提供目标,则 “make” 将默认构建 Makefile 中定义的第一个目标。

Makefile

📌Makefile是一个文本文件,文件名首字母M一般建议大写,也可以写成makefile,其中包含构建项目的依赖关系和依赖方法。每个依赖关系都描述了如何生成一个目标文件以及哪些文件或其他目标是其依赖方法。Makefile 使用如下:

  • 规则指定了依赖关系依赖方法
  1. 我们用C语言写一个简单的code.c文件:

  2. 以下是一个简单的示例 Makefile,用于构建一个名为 “mybin” 的可执行文件:
1 mybin: code.c #指定了依赖关系
2   gcc code.c -o mybin #依赖方法,比如以制表符开头。
3 clean:
4   rm -f mybin
  1. 示例中,"mybin"是目标,依赖于code.c,与code.c构成依赖关系。 依赖方法是构建“mybin”的命令:gcc code.c -o mybin(用gcc命令编译code.c文件)。“clean”是另一个目标,用于删除生成的可执行文件mybin
  2. 运行“make”命令,指定要构建的目标。(注:若不指定目标,系统将自动扫描Makefile中第一个目标)
[Asi@localhost ~]$ make
gcc code.c -o mybin
  1. 运行"make clean"命令。
[Asi@localhost ~]$ make clean
rm -f mybin

工作原理

原理

  • 如果我们再次执行几次make命令,发现编译不了了,会报出以下错误:
[Asi@localhost ~]$ make
make: `mybin' is up to date.
[Asi@localhost ~]$ make
make: `mybin' is up to date.
[Asi@localhost ~]$ make
make: `mybin' is up to date.
  • 为什么会出现这样的问题呢?对于没有更改的code.c文件,系统会进行识别,不会再进行编译链接,到这可能有小伙伴们会问,这么一个小文件,对编译器来说不算什么吧?但是你们想想,若项目中有几百个上千个文件呢,程序翻译的过程的周期是非常长的,所以编译器会进行识别对于没更改过的源文件可以跳过,大大缩短编译的时间。所以make/Makefile可以提高编译效率!
  • 编译器是如何知道源文件是否被更改过呢?make是如何工作的?
  1. 源文件可执行程序时间的对比,就能体现源文件的新旧(重新编译会重新写入一个二进制可执行文件,其修改时间也会被修改)
  2. 第一次编译的时候,一定是源文件的修改时间 小于 可执行程序的修改时间,当我们对源文件做任何修改之后,源文件的修改时间就 大于 可执行程序的修改时间,然后进行程序编译之后,那么源文件的修改时间又 小于可执行程序的修改时间。

文件的修改时间(ACM时间)

下面,我们执行stat + [文件名]命令,可查看一个文件的修改时间

Access time(Atime):这是文件的最后一次访问时间。当文件被读取、浏览或访问时,Atime时间会被更新。

Modify time(Mtime):这是文件的最后一次内容上修改时间。Mtime的更新,很可能会和Ctime或者Atime联动更改。

Change time(Ctime):这是文件的最后一次属性上修改时间。Ctime的更新,其他时间基本不会更新。

  1. 我们尝试给源文件code.c修改他的任意属性,比如给所属组添加了执行权限,再次stat命令查看code.c的时间,发现与原来时间相比,修改文件权限,只改变了Ctime,其他时间则是保持不变。
[Asi@localhost ~]$ ll
total 36
-rw-rw-r-- 1 Asi Asi  130 Sep 14 15:29 code.c
[Asi@localhost ~]$ chmod g+x code.c
  1. 下一步,我们试着修改一下code.c文件的内容,如下所示

    我们可以发现,Mtime的更新,AtimeCtime发生了联动更改。

  2. 然后,我们查看一下code.c文件,发现它的ACM时间都没有发生变化,再进行两次查看,时间也照样没有发生变化。
[Asi@localhost ~]$ cat code.c
#include <stdio.h>
int main()
{
    int i;
    for(i = 0; i <= 10; i++)
    {
      printf("num = %d\n",i);
    }
    printf("complete!\n");
  return 0;
}
[Asi@localhost ~]$ stat code.c
  File: ‘code.c’
  Size: 156         Blocks: 8          IO Block: 4096   regular file
Device: fd01h/64769d  Inode: 1063658     Links: 1
Access: (0674/-rw-rwxr--)  Uid: ( 1003/     Asi)   Gid: ( 1003/     Asi)
Access: 2023-09-14 15:39:11.012008120 +0800
Modify: 2023-09-14 15:39:11.010008051 +0800
Change: 2023-09-14 15:39:11.010008051 +0800
 Birth: -
  1. 🤔💡:那么为什么会这样子呢?
    PS:一般而言,一个文件被查看的频率是最高的。而文件是存放到磁盘中的,访问、更改文件本质其实就是访问磁盘,那么每次访问更改access time就是访问磁盘,这会让Linux系统充满大量的访问磁盘的IO操作,简介地减缓系统效率。所以,一些编译器一般会配置减少文件atime的更新频率,以提高性能。

不修改内容,更新文件的修改时间

我们再次回到前面一个问题,系统究竟是根据三个时间中的哪个时间来进行源文件与可执行程序的对比呢?当然最合理的是Modify time(Mtime)。

所以我们这里再次去执行make命令,编译不了,其根本原因是因为code.c的Mtime早于mybin的Mtime!

[Asi@localhost ~]$ make
make: `mybin' is up to date.
[Asi@localhost ~]$ stat code.c
  File: ‘code.c’
  Size: 156         Blocks: 8          IO Block: 4096   regular file
Device: fd01h/64769d  Inode: 1063658     Links: 1
Access: (0674/-rw-rwxr--)  Uid: ( 1003/     Asi)   Gid: ( 1003/     Asi)
Access: 2023-09-14 15:43:46.586536040 +0800
Modify: 2023-09-14 15:43:46.584535971 +0800
Change: 2023-09-14 15:43:46.584535971 +0800
 Birth: -
[Asi@localhost ~]$ stat mybin
  File: ‘mybin’
  Size: 8496        Blocks: 24         IO Block: 4096   regular file
Device: fd01h/64769d  Inode: 1063645     Links: 1
Access: (0775/-rwxrwxr-x)  Uid: ( 1003/     Asi)   Gid: ( 1003/     Asi)
Access: 2023-09-14 16:09:31.152943398 +0800
Modify: 2023-09-14 16:09:31.152943398 +0800
Change: 2023-09-14 16:09:31.152943398 +0800
 Birth: -

所以我们可以通过对Mtime进行修改以更新文件的时间,那么除了修改源文件的内容,我们可以使用touch命令,对,你没看错,touch命令不仅仅可以创建一个新文件,它也可以去更新已存在文件的时间!

touch [文件名]:所有时间都更新

touch -a [文件名]:更新atime

touch -m [文件名]:更新mtime

[Asi@localhost ~]$ make
make: `mybin' is up to date.
[Asi@localhost ~]$ touch  -m code.c
[Asi@localhost ~]$ make
gcc code.c -o mybin
[Asi@localhost ~]$ make
make: `mybin' is up to date.
[Asi@localhost ~]$ touch code.c
[Asi@localhost ~]$ make
gcc code.c -o mybin

.PHONY

📌.PHONY 的主要作用是告诉 make 工具,不管是否存在对应的文件,总是执行这些目标中的命令,其依赖方法总是会被执行,不会被任何情况拦截。它用于指定一个伪目标(phony target)。

.PHONY: target_name
  • 样例测试:
    .PHONY指定了mybin为伪目标,所以我们执行make命令,无论是否存在可执行程序,始终会执行依赖方法相关联的命令。
  • 结果:
[Asi@localhost ~]$ make
gcc code.c -o mybin
[Asi@localhost ~]$ make
gcc code.c -o mybin
[Asi@localhost ~]$ make
gcc code.c -o mybin
[Asi@localhost ~]$ make
gcc code.c -o mybin

项目清理

  • 在开发中,我们的工程会根据情况来清理的,像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行。
  • 不过,我们可以显示用make执行。即命令“make clean”,我们在测试时,以此来清理所有的目标文件,以便重新编译。

特性

用 make/makefile 写出整个程序的翻译过程

“make” 和 “Makefile” 具有依赖性的推导能力的。当运行make命令,make会自动检测依赖关系,mybin根据依赖关系去寻找code.o,如果code.o文件不存在,它不会执行依赖方法,回向下寻找code.o,如果向下没有找到code.o,编译器可能会报错,可能会隐式形成。那么code.o找到之后,它会根据依赖关系去寻找code.scode.s继续向下寻找……以此类推。直到找到code.c,执行依赖方法模块的命令之后形成code.i,然后在逆向回去扫描,执行其他尚未执行成功的依赖方法。此过程就如同入栈、出栈的过程,所以"make" 和 “Makefile” 就是根据这么一套逻辑执行完依赖关系和依赖方法。

执行结果

[Asi@localhost ~]$ make
gcc code.c -E -o code.i
gcc code.i -S -o code.s
gcc code.s -c -o code.o
gcc code.o -o mybin
目录
相关文章
|
29天前
|
Web App开发 编解码 Linux
使用Selenium自动化测试解决报告生成失败问题及Linux部署指南
这篇文章介绍了使用Selenium自动化测试解决报告生成失败问题的方法,包括Linux环境下的部署指南和代码实现。
21 1
使用Selenium自动化测试解决报告生成失败问题及Linux部署指南
|
18天前
|
安全 Linux 测试技术
Kali Linux预装的自动化渗透测试工具
Kali Linux预装的自动化渗透测试工具
28 2
|
29天前
|
Ubuntu Linux 持续交付
在Linux中,如何在Linux中使用Ansible进行自动化部署?
在Linux中,如何在Linux中使用Ansible进行自动化部署?
|
29天前
|
运维 Linux 持续交付
在Linux中,如何进行配置管理和自动化部署?
在Linux中,如何进行配置管理和自动化部署?
|
30天前
|
存储 Linux 测试技术
在Linux中,如何使用expect进行自动化交互式应用程序测试?
在Linux中,如何使用expect进行自动化交互式应用程序测试?
|
1月前
|
Linux 程序员 Python
python-office支持Mac和Linux吗?自动化办公用这个就够了
大家好,我是程序员晚枫。今天解答关于`python-office`是否支持Mac和Linux的问题。起初因需调用Office功能,该项目不完全支持这两个系统。现已通过拆分子项目解决了这一限制,例如`poexcel`可在多平台上运行Excel相关功能。只需简单修改导入语句,如使用`import poexcel`替代`import office`,即可在Mac和Linux上顺利执行。学习或使用中有任何疑问,欢迎留言交流!
|
30天前
|
jenkins Linux 持续交付
在Linux中,如何使用Jenkins和Ansible进行虚拟化环境的自动化和持续集成/持续部署(CI/CD)?
在Linux中,如何使用Jenkins和Ansible进行虚拟化环境的自动化和持续集成/持续部署(CI/CD)?
|
1月前
|
存储 监控 Linux
|
1月前
|
存储 运维 监控
|
29天前
|
监控 安全 Linux
在Linux中,如何编写自动化脚本来执行重复性任务?
在Linux中,如何编写自动化脚本来执行重复性任务?