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

听风八百遍,才知是人间 🌏

📃个人主页island1314

🔥个人专栏:Linux---登神长阶

⛺️ 欢迎关注:👍点赞 👂🏽留言 😍收藏 💞 💞 💞


🚀前言

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

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

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

1. Make和Makefile的基本概念

🎈1.1 Make是什么?

  • make 是一个命令工具,是一个解释 makefile 中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi 的 make,Visual C++的nmake,Linux下GNU的make。可见,Makefile都成为了一种在工程方面的编译方法。

🎈1.2 Makefile是什么?

  • Makefile 是一个 文件。它是一个工程文件的编译规则,它记录了原始码如何编译的详细信息、描述了整个工程的编译链接等规则。
  • Makefile 是 Linux 下用于管理文件依赖和编译顺序的一个重要工具。它用于定义项目中的各个源文件如何编译链接,可以极大地提高开发效率。
  • Makefile 带来的好处就是------"自动化编译" 。一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率🔥🔥

🎈1.3 Makefile的语法了解

cpp 复制代码
target(目标文件):文件1 文件2(依赖文件列表)		//依赖关系
 
<Tab>gcc -o 欲建立的执行文件 目标文件1 目标文件2		///依赖方法
	 command
	 ...
	 ...

target就是我们想要建立的信息,一般称作 目标文件。而后面的依赖文件列表就是具有相关性的 object files,也就是目标文件所依赖的文件(可以是一个或多个,也可以没有)

简述一下其基本的语法规则:

  • 目标文件与依赖文件列表文件之间要使用 :(冒号) 来隔开目标文件:依赖文件列表
  • target可以是一个目标文件、执行文件,甚至可以是一个标签【后面会提到的伪目标】。
  • 依赖方法前面必须加Tab空格键
  • 依赖方法以gcc 为例,也可以是其他的shell指令【command】。

综上所述:

我们可以了解到Makefile 文件 中定义了一系列规则,指定文件编译顺序、文件依赖关系及各文件的编译方法。而 make 命令是一个解释 Makefile 文件的命令工具,可以完成项目的自动化构建

2. Make和Makefile的使用

2.1 基本使用

  • 创建Makefile

touch Makefile

  • 编写Makefile:

vim Makefile

  • 编写要生成的可执行程序mybin和项目清理clean:

(注:clean 只是我们声明出来的名字,当然也可以声明为其他的)

注意:

  • 对于test:test.c ,冒号左侧是目标文件 ,右侧是它的依赖文件 ,所以就可以说它们之间存在一种 【依赖关系】,只有 test.c 存在才可以有 test。
  • 那要如何通过 test.c去生成 test 呢❓ 此时就需要使用到下面的这句 gcc指令gcc -o test test.c 👉它叫做 【依赖方法】
  • 使用make命令生成可执行程序

make

  • 使用make命令进行项目清理

make clean

2.2 基本语法规则

Makefile 中包括依赖关系(目标依赖)依赖方法(命令)

下面是 Makefile 中一些要素的基本语法规则:

🧩2.2.1 第一行不空行

原因:第一行通常是一个目标,例如 all: 或者 clean:。在 Makefile 中,空行被视为分隔符,用于区分不同的规则或目标。

当 Make 工具解析 Makefile 文件时,它会忽略空行,并将第一行之后的非空行视为第一个规则或目标。如果第一行是一个空行,可能会导致 Make 工具不正确地解释 Makefile,从而产生意外的行为或错误。

🧩2.2.2 目标

**目标:**指定了要生成的文件或要执行的操作名。

例如:上面的test就是要生成的目标文件名。

🧩2.2.3 命令

命令(依赖方法):包含了生成目标所需的具体操作步骤,通常是一条或多条 Shell 命令。

第二行必须以Tab开头不能是空格(注意: 按四下空格会报错**)**,紧接着是生成目标文件的命令。

例如:上面的gcc test -o test.c

🧩2.2.4 伪目标

伪目标: 伪目标是指在 Makefile 中**.PHONY** 定义的不对应实际文件的目标,通常用于执行一些特定的操作,比如清理临时文件

例如:上面的clean目标用于执行清理操作,删除test文件。
注:make默认执行的是第一行的命令,一般把清理工作放在最后面

🧩2.2.5 其他

注释: 使用 # 符号来添加注释,注释从 # 开始一直到该行的末尾。

变量: 可以使用变量来存储命令选项、编译器名称等信息,然后在规则中引用这些变量。

语法格式:VAR_NAME = value

取消回显: 由于调用make命令,其会默认显示回显,因此一般通过使用 **@**加在命令前面取消回显

**条件判断:**可以使用条件判断(ifeq、ifdef 等)来根据不同的条件执行不同的命令。

**函数:**Makefile 支持一些内置函数,可以用于字符串处理、文件查找等操作。

使用make和make clean,就可以方便地完成项目自动化构建和清理。

3. Makefile 工作原理

  1. makefile 或者Makefile文件会被make从上到下扫描,如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到"test"这个文件,并把这个文件作为最终的目标文件
  2. 如果test文件不存在,或是test所依赖的后面的test.o文件的文件修改时间要比test这个文件新(可以用 touch 测试),那么,他就会执行后面所定义的命令来生成test这个文件。
  3. 如果test所依赖的test.o文件不存在,那么make会在当前文件中找目标为test.o文件的依赖性,如果找到则再根据那一个规则生成test.o文件。(这有点像一个堆栈的过程)
  4. 当然,你的C文件和H文件是存在的啦,于是make会生成 test.o 文件,然后再用 test.o 文件声明make的终极任务,也就是执行文件test了
  5. 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
  6. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
  7. make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。

注意:make 默认只生成一个可执行程序

🌸3.1 make/Makefile识别文件新旧

make命令不是每次都会重新编译,只有更改过的文件才会重新编译。(提高编译效率)

若源代码没有更改也重新编译,那么每次预处理编译汇编链接的时间比较长,成本高

make/Makefile是如何知道文件更改过的?
答:通过源文件的修改时间和形成的可执行程序(也是文件)的修改时间做对比。

重新编译的本质:重新写入一个二进制的可执行文件(bin文件),文件的修改时间会跟着更改。

  1. 第一次的时候,一定是先有源文件,才有bin文件。
    源文件的修改时间 < bin文件的修改时间
  2. 第二 ~~ N 次的时候,我们对源文件做任何修改的时候,
    源文件的修改时间 > bin文件的修改时间
    重新编译形成可执行

大部分情况下重新编译都没问题,问题的产生不仅仅是修改新文件就能解决的。有些历史问题需要重新清理项目才可以解决。

文件 = 内容 + 属性,所以文件的ACM时间肯定与内容或属性有关。

**Access(最近访问时间):**普通文本文件打开:cat、vim,或者对目录进入、ls显示等

**Modify (对内容修改):**当文件内容发生变化时,修改时间(mtime)会被更新。

**Change(对属性修改):**当文件的权限、所有者、链接数或文件名甚至文件大小发生变化时,更改时间(ctime)会被更新。

注:

  • 三种时间会出现联动,例如对内容修改,Access和Change时间也会更改。

  • Access时间不是每次访问时都更改 ,读取查看文件操作最频繁,如果每次都改的话,比较浪费时间,因为文件一般都在磁盘存放,更改时间的本质 就是访问磁盘 。但是访问磁盘的速度比较慢(相对cpu而言),读取查看文件操作又是很频繁,如果每次都更改Access time的话,系统效率就会降低很多,所以就会隔一段时间更改一次。

    (具体间隔时间和是否间隔,由内核版本决定)

  • 使用touch命令可以修改ACM时间。
    -a 选项 修改Access时间 ,但同时也修改了change时间,因为access时间也是属性。
    -m 选项 修改Modify时间,但是Change时间也会跟着改。

综上,我们知道 make 是通过对比源文件和bin文件的Modify时间确定文件新旧的。

🌸3.2 .PHONY修饰的伪目标总是被执行

.PHONY配置项的目标clean并不是其他文件生成的实际文件,使make命令会自动绕过隐含规则搜索过程,也就是说执行命令make clean会自动忽略名为"clean"文件的存在,因此声明 .PHONY 配置项会改善性能,并且不需要担心实际同名文件存在与否😮。

【通俗一点说】:.PHONY 修饰的目标clean并不是某个依赖项生成的实际文件,因此make命令不再去搜寻当前文件夹下是否有clean文件,这样少去做一些事,自然会改善性能,并且不用担心当前文件夹下是否有同名的文件。

通过时间对比,可以做到不让有些代码进行重新编译(不让某些操作进行)。

如上:右边的test被.PHONY修饰,则多次make时,都会执行gcc命令,把可执行程序重新形成。

🌸3.3 make/Makefile具有依赖性的推导能力

💢 越是接近目标文件的命令,就越是要写在前面。因为程序是按照递归的方式进行依赖文件查找的,看到第一行有一个没见过的依赖文件,就往下一行进行查找,以此类推。

对于gcc的编译,我们都知道要生成一个可执行程序需要经过预处理、编译、汇编和连接 ,中间会产生.i,.o,.s文件 。但是在上面的操作中都没有生成中间文件
但是我们知道一件事:生成bin文件,就需要对应的.o文件。

以Makefile的推导过程如下:(类似一个栈结构)

cpp 复制代码
test.o: test.s
  gcc -c test.s -o test.o
   
test.s: test.i
  gcc -S test.i -o test.s
   
test.i: test.c
  gcc -E test.c -o test.i
                                                                                                                                                                                                                 .PHONY:clean
clean:
  rm -f test test.o test.s test.i

但是一般都不会写成这么复杂,一般都是如下写法:

4. Makefile小知识

🍉 4.1 替换

符号 含义
= 替换
%.o 任意的.o文件
%.c 任意的.c文件

🥝 4.2 通配符

符号 含义
$^ 所有依赖文件
$@ 所有目标文件
$< 所有依赖文件的第一个文件

此外:Makefile中可以编写变量,表达式之间不建议带空格

通过 $(变量名) 来引用变量的值。

$@ 和 $^,前者表示:左侧被编译的所有内容,即【目标文件】,后者表示:之后所有内容,即【依赖文件】。

此时,当我们再去make的时候,就可以发现这个特殊符号自动替换成了:两侧的【目标文件】和【依赖文件】。

🍍4.3 生成多个可执行程序

一般来说make 默认只生成一个可执行程序如下:

但是我们可以做出以下修改:


📖总结

以上就是Make 和 Makefile的全部内容啦,后面我们就要讲到进度条的相关内容,就会运用到这一节的知识,敬请期待咯!!!

💞 💞 💞那么本篇到此就结束,希望我的这篇博客可以给你提供有益的参考和启示,感谢大家支持!!!祝大家天天开心

相关推荐
dessler20 分钟前
Docker-如何启动docker
运维·docker·云原生·容器·eureka
zhy2956320 分钟前
【DOCKER】基于DOCKER的服务之DUFS
运维·docker·容器·dufs
秋名山小桃子35 分钟前
Kunlun 2280服务器(ARM)Raid卡磁盘盘符漂移问题解决
运维·服务器
与君共勉1213836 分钟前
Nginx 负载均衡的实现
运维·服务器·nginx·负载均衡
努力学习的小廉43 分钟前
深入了解Linux —— make和makefile自动化构建工具
linux·服务器·自动化
MZWeiei1 小时前
Zookeeper基本命令解析
大数据·linux·运维·服务器·zookeeper
Arenaschi1 小时前
在Tomcat中部署应用时,如何通过域名访问而不加端口号
运维·服务器
小张认为的测试1 小时前
Linux性能监控命令_nmon 安装与使用以及生成分析Excel图表
linux·服务器·测试工具·自动化·php·excel·压力测试
waicsdn_haha1 小时前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk
biter00881 小时前
opencv(15) OpenCV背景减除器(Background Subtractors)学习
人工智能·opencv·学习