Linux基础开发工具之Linux自动项目构建工具的使用

目录

前言

1.make/makefile

1.1 依赖关系/依赖方法

2.原理

3.项目清理

 4.make的执行问题

 5.相关简单的符号介绍

总结


前言

  之前给大家介绍了我们在开发过程中所需要使用到的编辑器vim,以及编译器gcc/g++的使用,但是我相信大家在使用过程会发现我们在每次编写好一份代码时总是需要每次去调用gcc/g++的相关指令去编译,那么如果我们具有了多份代码时,我们还需要一个一个去编写就显得非常的麻烦,那么我们今天要学的相关工具就会免去我们在这个方面的很多工作。


1.make/makefile

    学习我们的自动项目构建工具学习的就是我们对make以及makefile这个工具的使用,而会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。
   一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
    make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
 从本质来讲我们的make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。

那么我们如何去使用我们这个工具呢?那么首先就需要我们自己去创建一个makefile文件。

 那么创建好这个文件后,我们后续需要做什么操作呢?为了让大家更好的理解

1.1 依赖关系/依赖方法

 这里我们如何去理解这个依赖关系和依赖方法呢?这里我就简单的给大家举一个例子:

首先我们先创建一个文件写一份代码:

 这里我们对makefile进行配置:

 这里我们可以看到我们对我们hello.c到hello运行程序进行了编写,那么这里我们的依赖关系就是:

 那么我们的依赖方法对应的就是每行依赖关系对应得下一行:

也就是: gcc  -option hello.* -option hello.*

                rm - fr hello.i hello.s hello.o hello

那么我们编写好得makefile文件该如何使用呢?这里我们使用make指令看看效果:

 这里我们使用make指令可以发现我们这里产生了我们编译的各个过程所对应的文件,那么这里我们调用我们的可执行程序看看运行结果如何:

 这里我们可以发现我们的程序执行无误,那么我们此处的原理又是什么呢?

2.原理

1.首先make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
2. 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“hello”这个文件,并把这个文件作为最终的目标文件

3. 如果hello文件不存在,或是hello所依赖的后面的hello.o文件的文件修改时间要比hello这个文件新,那么,他就会执行后面所定义的命令来生成hello这个文件。

 4.如果hello所依赖的hello.o文件不存在那么make会在当前文件中找目标为hello.o文件的依赖性,如果找到则再根据那一个规则生成hello.o文件。(这有点像一个堆栈的过程)
5. 当然,你的C文件和H文件是存在的啦,于是make会生成 hello.o 文件,然后再用 hello.o 文件声明make的终极任务,也就是执行文件hello了。
6. 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
7. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
8. make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。

那么总结的来说就是我们在调用make指令该会自动推导makefile中的依赖关系,去产生我们的目标文件。

3.项目清理

这里我们产生了一堆文件,但是我们的工作也是需要被清理的,这个清理过程就需要我们调用我们先前就编写好的clean

也就是

这里我们发现我们的清除程序调用方式是make +clean ,那么这里的原因是什么呢?这里有个小知识需要我们去了解一下:

make从顶向下扫描,默认将第一个作为make指令,后续的就需要我们使用make+文件名,就如我们需要使用make  clean达到清理效果

但是一般我们的clean目标文件我们一般将其设置为伪目标,也就需要使用.PHONY关键字去修饰。

这里我们为什么需要使用.PHONY关键字去修饰clean呢?首先我们需要知道的就是我们的.PHONY关键字的作用就是让我们无论在什么情况下都能被执行,那么也就是说我们的依赖关系并不是在什么情况下都能执行的,而是需要一定条件的,所以我们不建议把形成可执行逻辑用伪目标修饰,但是就是我们的清理程序是我们要求每次都要被执行的,所以我们一般用伪目标关键字去修饰clean。

所以我们简单的修改一下我们的makefile文件:

 4.make的执行问题

我们之前说我们的make并不是在任何情况下都能执行的,这里我给大家实验一下:

 这里我们在第一次执行过make后发现我们第二次并不能执行了,而且上面提示我们hello是更新了的,那么原因是什么呢?首先我们需要知道我们make在执行所对应的依赖关系是需要我们操作系统付出代价的,在我们源文件没有改变的情况下,我们再次编译得到可执行程序也是不变的,那么我们再次make得到的可执行程序是没有意义的,我们的操作系统也不允许这样的事情发生。

那么如果要在是make有效就需要我们修改我们的源文件内容,而这个过程实际上就是修改了我们源文件的相关时间,从而我们的源文件时间就比我们的可执行程序文件更新,这样子我们就可以产生新的可执行程序,所以我们可以说我们的make指令是否有效实际上就是我们的源文件时间是否比我们的可执行程序文件更新。

而我们的文件又分为三个时间,分别是:

access指的是我们的访问时间

modify指的是我们对文件内容进行修改的时间

change指的是我们对文件属性进行修改的时间

我们可以使用stat指令去查看相关时间信息:

  这里需要给大家简单的说明一下这里我们由于访问我们文件的是非常频繁的所以修改access时间会影响我们的整机效率,所以在我们现在的操作系统中access的修改并不是每次都需要修改而是要达到一定的条件(每个操作系统的不一样)。

那么我们对我们的源文件进行修改实际上就会更改我们的Modify时间,但是在修改源文件的过程中一般我们文件属性相关的内存也会发生相关变化所以我们的Change的时间也会发生变化。

那么我们就简单的给大家演示一下,这里我们对我们的源文件内容进行修改:

 这里我们发现我们的时间发生了改变,那么我们调用我们的make指令看看效果:

可以发现我们的make成功了。

此外为了验证我们的程序编译成功和我们内容变化没有关系我们可以使用我们的touch指令去修改相关时间:

 这里我们看到我们的时间发生了变化,那么调用我们的make指令看看效果:

 可以发现我们的make指令也成功了,此外我们可以使用touch+对应的选项去修改我们的对应的时间,也就是:

-a更新访问时间,-m更新修改内容时间(这里我们的change时间也会随着改变)

 5.相关简单的符号介绍

 总体来讲我们的make小编已经给大家讲解的大差不差了,但是这里还有几个符号需要大家去使用理解一下:

$@:表示的是我们依赖关系左边的简写

 $^:表示的是我们依赖关系右边的简写

 @:如果我们不想让我们使用make时我们的依赖方法显示到屏幕上,只需要我们在我们的依赖方法的第一行加上@即可

 #:mikefile中的注释


总结

 对于内容呢,小编就给大家介绍到这里了关键是需要大家平时多使用加深影响并且学习,才能掌握我们的LInux操作系统的相关内容。|
 


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/58430.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

centos7实现负载均衡

目录 一、基于 CentOS 7 构建 LVS-DR 集群。 1.1 配置lvs负载均衡服务 1.1.1 下载ipvsadm 1.1.2 增加vip 1.1.3 配置ipvsadm 1.2 配置rs1 1.2.1 编写测试页面 1.2.2 手工在RS端绑定VIP、添加路由 1.2.3 抑制arp响应 1.3 配置rs2 1.4 测试 二、配置nginx负载…

机器学习深度学习—语言模型和数据集

👨‍🎓作者简介:一位即将上大四,正专攻机器学习的保研er 🌌上期文章:机器学习&&深度学习——文本预处理 📚订阅专栏:机器学习&&深度学习 希望文章对你们有所帮助 语…

ASP.NET Core学习路线图

说明 1. 先决条件 - [C#](https://www.pluralsight.com/paths/csharp) - [Entity Framework](https://www.pluralsight.com/search?qentity%20framework%20core) - [ASP.NET Core](https://www.pluralsight.com/search?qasp.net%20core) - SQL基础知识 2. 通用开发技能 -…

Android 数据库之GreenDAO

GreenDAO 是一款开源的面向 Android 的轻便、快捷的 ORM 框架,将 Java 对象映射到 SQLite 数据库中,我们操作数据库的时候,不再需要编写复杂的 SQL语句, 在性能方面,greenDAO 针对 Android 进行了高度优化,…

MySQL的查询方法

单表查询 素材: 表名:worker-- 表中字段均为中文,比如 部门号 工资 职工号 参加工作 要求: 1、显示所有职工的基本信息。 2、查询所有职工所属部门的部门号,不显示重复的部门号。 3、求出所有职工的人数。 4、…

java动态生成excel并且需要合并单元格

java动态生成excel并且需要合并单元格 先上图看一下预期效果 集成poi <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifactId><version>4.0.0</version> </dependency> <dependency><…

docker部署jenkins且jenkins中使用docker去部署项目

docker部署jenkins且jenkins中使用docker去部署项目 1、确定版本 2.346.1是最后一个支持jdk8的 2、编写docker-compose.yml并执行 在这个目录中新增data文件夹&#xff0c;注意data是用来跟docker中的文件进行映射的 docker-compose.yml version: "3.1" service…

leetcode 746. 使用最小花费爬楼梯

2023.8.8 昨天爽玩一天&#xff0c;在家就是舒服。 今天继续刷动态规划题。 动态规划题最重要的就是搞清楚dp[i] 的定义&#xff0c;本题dp[i] 的含义是&#xff1a;到达第i层&#xff0c;所需的最小花费。 那么由于起始台阶可以是0或者1&#xff0c;那么dp[0]和dp[1]都初始化…

QT笔记——QT自定义事件

我们有时候想发送自定义事件 1&#xff1a;创建自定义事件&#xff0c;首先我们需要知道它的条件 1&#xff1a;自定义事件需要继承QEvent 2&#xff1a;事件的类型需要在 QEvent::User 和 QEvent::MaxUser 范围之间&#xff0c;在QEvent::User之前 是预留给系统的事件 3&#…

一零六七、JVM梳理

JVM&#xff1f; Java虚拟机&#xff0c;可以理解为Java程序的运行环境&#xff0c;可以执行Java字节码&#xff08;Java bytecode&#xff09;并提供了内存管理、垃圾回收、线程管理等功能 java内存区域划分?每块内存中都对应什么? 方法区&#xff1a;类的结构信息、常量池、…

享元模式(C++)

定义 运用共享技术有效地支持大量细粒度的对象。 使用场景 在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中&#xff0c;从而带来很高的运行时代价——主要指内存需求方面的代价。如何在避免大量细粒度对象问题的同时&#xff0c;让外部客户程序仍…

【C++】多态的底层原理(虚函数表)

文章目录 前言一、虚函数表二、派生类中虚函数表1.原理2.例子&#xff1a; 三、虚函数的存放位置四 、单继承中的虚函数表五、多继承中的虚函数表六、问答题 前言 一、虚函数表 通过观察测试我们发现b对象是8bytes&#xff0c;除了_b成员&#xff0c;还多一个__vfptr放在对象的…