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

打印 上一主题 下一主题

主题 595|帖子 595|积分 1785

目录
弁言
Makefile 简介
依赖关系与依赖方法
make运行规则
依赖关系示例
依赖方法
Makefile 工作原理
示例代码
清算项目与伪目标
清算示例
.PHONY总是被实行
文章手稿:

文章手稿见文末~
弁言

项目构建时遇到的各种挑战如文件编译顺序、库链接、依赖文件的管理等,在不同开发情况中会有不同的办理方案。
在 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的默认操纵

依赖关系示例

假设我们有以下文件依赖关系:
  1. hello: hello.o
  2. hello.o: hello.s
  3. hello.s: hello.i
  4. hello.i: hello.c
复制代码
依赖方法

使用 gcc 命令编译不同中间文件:
  1. hello: hello.o
  2.         gcc hello.o -o hello
  3. hello.o: hello.s
  4.         gcc -c hello.s -o hello.o
  5. hello.s: hello.i
  6.         gcc -S hello.i -o hello.s
  7. hello.i: hello.c
  8.         gcc -E hello.c -o hello.i
复制代码
在上述例子中,hello 是终极目标文件,它依赖于目标文件 hello.o,而后者又进一步依赖于 hello.s,云云递归下去直到源文件 hello.c。
Makefile 工作原理


  • make 命令查找名为 Makefile 或 makefile 的文件。
  • 读取文件并找到第一个目标文件,在本例中是 hello。
  • 如果 hello 不存在,或其依赖文件中任何一个文件比 hello 更新,则生成 hello 文件。
  • 递归检查每个依赖文件,按顺序举行必要的编译步调。
  • 如果出现错误,make 退出并报错。
  • 如果依赖文件仍然不在,make 也将退出。
示例代码

这是一个简单的 C 代码示例和相应的 Makefile 文件:
  1. // hello.c
  2. #include <stdio.h>
  3. int main() {
  4.     printf("hello Makefile!\n");
  5.     return 0;
  6. }
复制代码
  1. # Makefile
  2. hello: hello.o
  3.         gcc hello.o -o hello
  4. hello.o: hello.c
  5.         gcc -c hello.c -o hello.o
  6. .PHONY: clean
  7. clean:
  8.         rm -f hello.o hello
复制代码
在这个示例中,hello 目标文件依赖于 hello.o 文件,而 hello.o 则由 hello.c 编译生成。clean 是一个伪目标,无论何时实行 make clean,clean 中的命令都会被实行,达到清算文件目的。
清算项目与伪目标

工程经常需要清算生成的中间文件和目标文件,Makefile 提供了方便的清算机制。通过定义伪目标,可以确保 make clean 总能实行对应的清算命令。
清算示例


代码:
  1. .PHONY: clean
  2. clean:
  3.         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) 识别的新旧。 根据原文件和可实行程序的近来修改时间,评估要不要重新生成。
  文章手稿:

 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

自由的羽毛

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表