【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
目录
相关文章
|
25天前
|
Rust Ubuntu Java
[Linux工具] Makefile
Makefile是Linux环境下用于自动化编译和链接程序的配置文件,常用于简化大型项目的编译流程。通过定义目标文件、依赖文件及生成命令,Makefile能高效管理编译任务。它不仅适用于C语言项目,还可扩展到其他编程语言和非编程任务中。
52 20
[Linux工具] Makefile
|
3月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
344 8
|
12天前
|
监控 安全 Ubuntu
Linux下如何安装配置Fail2ban防护工具
通过以上步骤,可以在Linux系统中成功安装和配置Fail2ban,从而有效保护服务器免受暴力破解等攻击。Fail2ban通过实时监控日志文件,自动更新防火墙规则,为系统安全提供了一层重要的保护。
65 36
|
8天前
|
Unix Linux C语言
【Linux】 Linux makefile 教程
本文详细介绍了 Linux 环境下 Makefile 的基本结构、语法和使用方法,并通过一个简单的 C++ 项目示例演示了 Makefile 的实际应用。Makefile 是一个强大而灵活的工具,通过合理配置,可以极大地简化项目的编译和管理过程,提高开发效率。希望本文能帮助您更好地理解和应用 Makefile,在实际项目中高效管理代码的编译和构建。
37 20
|
7天前
|
Unix Linux C语言
【Linux】 Linux makefile 教程
本文详细介绍了 Linux 环境下 Makefile 的基本结构、语法和使用方法,并通过一个简单的 C++ 项目示例演示了 Makefile 的实际应用。Makefile 是一个强大而灵活的工具,通过合理配置,可以极大地简化项目的编译和管理过程,提高开发效率。希望本文能帮助您更好地理解和应用 Makefile,在实际项目中高效管理代码的编译和构建。
39 16
|
24天前
|
Linux 网络性能优化 网络安全
Linux(openwrt)下iptables+tc工具实现网络流量限速控制(QoS)
通过以上步骤,您可以在Linux(OpenWrt)系统中使用iptables和tc工具实现网络流量限速控制(QoS)。这种方法灵活且功能强大,可以帮助管理员有效管理网络带宽,确保关键业务的网络性能。希望本文能够为您提供有价值的参考。
76 28
|
21天前
|
网络协议 Unix Linux
深入解析:Linux网络配置工具ifconfig与ip命令的全面对比
虽然 `ifconfig`作为一个经典的网络配置工具,简单易用,但其功能已经不能满足现代网络配置的需求。相比之下,`ip`命令不仅功能全面,而且提供了一致且简洁的语法,适用于各种网络配置场景。因此,在实际使用中,推荐逐步过渡到 `ip`命令,以更好地适应现代网络管理需求。
34 11
|
1月前
|
安全 网络协议 Linux
结合 `nc` 工具利用笑脸漏洞(Smile Bug)攻击 Metasploitable2 Linux
本文介绍如何使用 `nc`(Netcat)工具结合笑脸漏洞(Smiley Bug)攻击 Metasploitable2 Linux 靶机。首先概述了 `nc` 的基本功能和高级用法,包括建立连接、监听端口、文件传输等操作。接着详细描述了笑脸漏洞的原理及其在网络攻防中的应用,展示了通过 `nc` 发送恶意输入检测漏洞的方法。最后结合 Python 脚本实现更复杂的攻击场景,并强调了合法性和环境隔离的重要性。
51 13
|
2月前
|
Linux Android开发 开发者
linux m、mm、mmm函数和make的区别
通过理解和合理使用这些命令,可以更高效地进行项目构建和管理,特别是在复杂的 Android 开发环境中。
81 18
|
2月前
|
运维 监控 Linux
推荐几个不错的 Linux 服务器管理工具
推荐几个不错的 Linux 服务器管理工具
173 6