当前位置: 首页 > news >正文

【Linux】自动化构建工具 —— make/makefileLinux第一个小程序 - 进度条

在这里插入图片描述

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:Linux
🎯长路漫漫浩浩,万事皆有期待

上一篇博客:Linux编译器 gcc/g++的使用&&初识动静态链接库

文章目录

  • 一、前言
  • 二、概念
  • 三、代码实现
  • 四、实现原理
    • 1、依赖关系和依赖方法
    • 2、清理
      • ① .PHONY 伪目标
      • ② .PHONY 的取舍
    • 3、make 确定是否编译的方法
    • 4、完整代码
  • Linux第一个小程序 - 进度条
    • 行缓冲区的概念
    • \r和\n
    • 进度条代码及效果展示
  • 总结:

一、前言

上篇博客,我们学习了 gcc 编译器。学会了如何在 Linux 上编译C语言代码。如果有上百个源文件,难道一个个都用 gcc 编译为 .o 文件,最后将它们一起链接起来?

有没有一种方法,使编译更加快捷,一定程度实现自动化编译?
可以使用 make/makefile 构建一个简单的自动化工具。

二、概念

makefile :

makefile 是一个文件。它是一个工程文件的编译规则,描述了整个工程的编译链接等规则。
写好的 makefile 文件可以使用一行命令来完成 “自动化编译” ,从而完成对工程的编译,极大提高效率。

make :

make 是一个命令工具,用来一个解释 makefile 中文件中的指令。
当已经编写好 makefile 文件后,只需要使用 make ,就可以执行 makefile 中的内容。

一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。所以使用好 make/makefile ,可以使得开发更加得心应手。

总结make 是一条指令makefile 是一个文件,两个搭配使用,完成项目自动化构建。

三、代码实现

在讲解 make/makefile 之前,我们先写一个小 demo ,以这个 demo 为基准,对其进行讲解。

makefile 文件需要创建在当前工程的目录下,makefile 文件的名称可以为 makefile 或 Makefile

假设当前工程下已经有了一个 test.c ,我们直接开始 demo 的编写:
在这里插入图片描述

这样 makefile 就编写好了,就两句话,这时编写的 makefile 可以完成对程序的编译。

我们返回终端,使用 make 就可以对 test.c 进行编译:

在这里插入图片描述

使用 make 指令后,makefile 的第二行内容被打印在终端,并且生成了可执行程序 test ,test 程序也是可以执行的。

四、实现原理

1、依赖关系和依赖方法

在 Makefile 文件中,有这样一句话:

test:test.c

刚刚测试过我们知道 test 是目标文件,而 test.c 则是原始文件。

而 test.c 经过 gcc test.c -o test 生成 test 文件。

它们的关系 :

  • test 依赖 test.c 生成,所以 test.c 是 test 的依赖文件 。它们之间的关系被称为 依赖关系 。
  • test.c 生成 test 需要通过 gcc test.c -o test 指令,这条指令就是 依赖方法 。

依赖关系 和 依赖方法 如何理解呢?

我们通过一个 makefile 理解一下:

在这里插入图片描述

在 makefile 文件中,共有四组依赖关系和依赖方法 ,当使用 make 调用 makefile 文件中内容时,便开始执行 makefile 中的内容:

test 依赖于 test.o ,但是 test.o 并不存在,跳转到下一组依赖关系
test.o 依赖于 test.s ,但是 test.s 并不存在,跳转到下一组依赖关系
test.s 依赖于 test.i ,但是 test.i 不存在,跳转到下一组依赖关系
test.i 依赖于 test.c ,test.c 存在,这时开始执行依赖方法

由此开始,逐渐执行上面的依赖方法,一层层回退,逐渐生成 test.i 、test.s 、test.o ,最后生成可执行程序,make 执行完毕。我们发现,这一过程就像 数据结构的栈 。

当目标文件所依赖的文件不存在时,就会将依赖方法入栈,知道依赖关系匹配了,再执行相应的依赖方法,在按照栈的规则,逐渐将栈中的元素出栈,规则满足后进先出。

为了验证这些步骤是否都被执行,我们 make 一下看看:
在这里插入图片描述

依赖方法对应的文件都产生了,所以依赖关系和依赖方法必须同时具备并正确,缺一不可 。

2、清理

平时写代码时,经常需要反复编译,执行代码。

而在下一次重新编译之前,需要清理一下上次生成的可执行程序。但是清理的时候可能清理错误,不小心把源文件删了,这时又造成了问题。

而上面的步骤,我们也生成了很多附加文件(如 test.i 等)。

所以我们基于 demo 增加一个清理功能:
在这里插入图片描述

使用 make 测试一下:

在这里插入图片描述

文件也都删除了。

这是为什么,新增语句是什么意思?

① .PHONY 伪目标

.PHONY 修饰的对象是伪目标,伪目标的特性是:总是被执行的。

.PHONY 修饰的一定能被反复执行,但是能被反复执行的不一定被 .PHONY 修饰。

多次执行 make 和 make clean 试试:
在这里插入图片描述

:makefile 默认从上到下扫描只会执行第一组的依赖关系和依赖方法,所以默认执行第一组,这时使用 make 就可以;而 clean 为第二组,所以需要 make clean ,加上对应的关系。同理,对于第一组,使用 make test 也能执行。

第一组关系没有被 .PHONY 修饰,而不能重复执行。但是第二组 clean 可以重复执行 。
但是怎么证明 .PHONY 修饰对象之后,对象能被反复执行?我们再验证一下,给 test 加上修饰:
在这里插入图片描述

加上 .PHONY 修饰后,make 可以执行多次了,证明了 .PHONY 的作用。
在这里插入图片描述

但是能被反复执行的不一定被 .PHONY 修饰,就比如 clean :

在这里插入图片描述

当 clean 去掉修饰之后,依然能被反复执行。
在这里插入图片描述

② .PHONY 的取舍

一般对于编译来说,是不加 .PHONY 修饰的。

因为编译是十分耗时间,特别是当工程量很大的时候,编译一两小时都不为过。所以防止对未修改的程序反复编译 ,一般编译时不加修饰。

但是 清理clean 是可以多次执行的,因为删除不太浪费时间,且可以反复清理,确认是否清理完毕。并且为了肯定清理可以被多次执行,所以通常用 .PHONY 修饰。

3、make 确定是否编译的方法

上面我们测试 make 时,发现当编译过一次后,继续使用 make 就无法继续编译了。但是 clean 是可以不加修饰反复执行的。 make 是如何确定是否要编译?

对于程序来说,时间有两条线。第一条是源代码时间的一条线,第二条是形成的可执行程序的时间的一条线 。而它们之间的次序,是先有源代码,再有可执行程序。

所以只要可执行程序的最近修改时间比源文件的修改时间晚,就认为当前可执行程序是最新的,为了减少时间和其他开销,于是不执行编译;反之执行编译 。

我们再重新生成可执行程序,并重复 make ,观察它们的时间:
这里就要用到 stat 指令,它的 modify 就是最近修改时间 ,如果对 stat 指令不了解的可以看这一篇:【Linux】基本指令(一) (在 ls 指令部分)
在这里插入图片描述

可执行程序 test 的时间明显比 源代码 test.c 晚,所以 make 并不能起作用。

那么基于对这个概念的理解,我们能否用其他方法再次执行 make ?

touch 指令为创建一个文件。若文件不存在则会创建一个文件;若文件存在则会把文件时间更新到最新。

使用 touch 更新一下 test.c 的时间,用 stat 观察时间,并反复 make 试试:
在这里插入图片描述

在这里插入图片描述

由此,我们发现可以使用 touch 来 “欺骗” make 来反复编译。这也侧面证明了: make 对于是否编译的决策是基于修改时间,而并不是基于文件内容是否修改 。

4、完整代码

test:test.cgcc test.c -o test 
.PHONY:clean                                                      
clean:rm -f test.i test.s test.o test

对于依赖关系而言,: 左边为目标文件,: 右边为依赖文件
依赖方法前需要有一个 tab ,为固定格式
: 右边可以有多个依赖文件 ,: 右边通常被称为依赖文件列表
对于 : 右边,目标文件对应的依赖文件列表可以为空 (例如 clean)
makefile 默认执行第一组的依赖关系和依赖方法,对于第一组可以直接使用 make 执行,后面则需要 make + 目标文件
.PHONY 修饰的 伪目标可反复执行 ,但反复执行的不一定是伪目标

Linux第一个小程序 - 进度条

行缓冲区的概念

首先,我们来感受一下行缓冲区的存在,在Linux当中以下代码的运行结果是什么样的?
在这里插入图片描述

对于此代码,当然是先输出字符串hello world然后休眠3秒之后结束运行。那么对于以下代码呢?
在这里插入图片描述

可以看到代码中仅仅删除了字符串后面的’\n’,那么代码的运行结果还与之前相同吗?
答案是不相同,该代码的运行结果是:先休眠3秒,然后打印字符串hello world之后结束运行。该现象就证明了行缓冲区的存在。

显示器对应的是行刷新,即当缓冲区当中遇到’\n’或是缓冲区被写满才会被打印出来,而在第二份代码当中并没有’\n’,所以字符串hello world先被写到缓冲区当中去了,然后休眠3秒后,直到程序运行结束时才将hello world打印到显示器当中。

\r和\n

\r: 回车,使光标回到本行行首。
\n: 换行,使光标下移一格。

在这里插入图片描述

而我们键盘上的Enter键实际上就等价于\n+\r。

既然是\r是使光标回到本行行首,那么如果我们向显示器上写了一个数之后再让光标回到本行行首,然后再写一个数,不就相当于将前面一个数字覆盖了吗?但不使用’\n’进行换行怎么将缓冲区当中数据打印出来?

这里我们可以使用fflush函数,该函数可以刷新缓冲区,即将缓冲区当中的数据刷新到显示器中。
对此我们可以编写一个倒计时的程序。
在这里插入图片描述

在输出下一个数之前都让光标先回到本行行首,就得到了倒计时的效果。

请添加图片描述

进度条代码及效果展示

知道了\r这个概念我们就可以实现一个简单的进度条了。
在这里插入图片描述
效果展示:

在这里插入图片描述

总结:

今天我们学习了自动化构建工具 —— make/makefile ,重点了解了 make/makefile 的规则上。实际开发中,好的 make/makefile 可以让项目开发事半功倍。接下来,我们将继续学习其他Linux环境基础工具的基本使用及配置。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

相关文章:

【Linux】自动化构建工具 —— make/makefileLinux第一个小程序 - 进度条

​ ​📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:Linux 🎯长路漫漫浩浩,万事皆有期待 上一篇博客:Linux编译…...

tensorflow的unet模型

import tensorflow as tf from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D, Dropout, UpSampling2D, concatenate# 定义 U-Net 模型 def unet(input_size(256, 256, 3)):inputs Input(input_size)# 编码器部分conv1 Conv2D(64, 3, activationrelu, padding…...

(2023 最新版)IntelliJ IDEA 下载安装及配置教程

IntelliJ IDEA下载安装教程(图解) IntelliJ IDEA 简称 IDEA,由 JetBrains 公司开发,是 Java 编程语言开发的集成环境,具有美观,高效等众多特点。在智能代码助手、代码自动提示、重构、J2EE 支持、各类版本…...

react 实现拖动元素

demo使用create-react-app脚手架创建 删除一些文件,创建一些文件后 结构目录如下截图com/index import Movable from ./move import { useMove } from ./move.hook import * as Operations from ./move.opMovable.useMove useMove Movable.Operations Operationse…...

【EI会议】第二届声学,流体力学与工程国际学术会议(AFME 2023)

第二届声学,流体力学与工程国际学术会议 2023 2nd International Conference on Acoustics, Fluid Mechanics and Engineering(AFME 2023) 声学、流体力学两个古老的学科发展至今,无时无刻都在影响着我们的生活。小到日常使用的耳…...

Android StringFog 字符串自动加密

一、StringFog 作用 一款自动对dex/aar/jar文件中的字符串进行加密Android插件工具,正如名字所言,给字符串加上一层雾霭,使人难以窥视其真面目。可以用于增加反编译难度,防止字符串代码重复。 支持java/kotlin。支持app打包生成…...

上四休三,未来的期许

近日“少上一天班,究竟香不香”引发关注,英国媒体2月21日报道,一项全世界目前为止参加人数最多的“四天工作制”试验,不久前在英国取得了成功。很多人表示上过四天班之后,给多少钱也回不去五天班的时代了。 来百度APP畅…...

怎么防止360安全卫士修改默认浏览器?

默认的浏览器 原先选项是360极速浏览器(如果有安装的话),我这里改成了Chrome。 先解锁 才能修改。...

调整参数提高mysql读写速度

要提升MySQL的写入速度,您可以采取一些参数调整和优化措施,这些措施可以根据您的具体应用和环境进行调整。以下是一些常见的参数和优化建议: InnoDB存储引擎: 如果您使用的是InnoDB存储引擎,确保以下参数被设置得合理: innodb_buffer_pool_size:增加内存池大小,以便更多…...

第一届电子纸产业创新应用论坛-邀请函

...

Go expvar包

介绍与使用 expvar 是 exposed variable的简写 expvar包[1]是 Golang 官方为暴露Go应用内部指标数据所提供的标准对外接口,可以辅助获取和调试全局变量。 其通过init函数将内置的expvarHandler(一个标准http HandlerFunc)注册到http包ListenAndServe创建的默认Serve…...

Yolo v8代码逐行解读

train.py文件 1.FILE Path(__file__).resolve() __file__代表的是train.py文件,Path(__file__).resolve()结果是train.py文件的绝对路径。 2.ROOT FILE.parents[0] 获得train.py父目录的绝对路径 3.sys.path 是一个列表list,里面包含了已经添加到系…...

9.18号作业

完善登录框 点击登录按钮后,判断账号(admin)和密码(123456)是否一致,如果匹配失败,则弹出错误对话框,文本内容“账号密码不匹配,是否重新登录”,给定两个按钮…...

Spring源码阅读(spring-framework-5.2.24)

spring-aop spring-aspects spring-beans spring-context 等等 第一步: Tags spring-projects/spring-framework GitHub 找到相应的release版本 第二步: 下载相应版本的gardle,如何看版本 spring-framework/gradle/wrapper /gradl…...

【SpringMVC】文件上传与下载、JREBEL使用

目录 一、引言 二、文件的上传 1、单文件上传 1.1、数据表准备 1.2、添加依赖 1.3、配置文件 1.4、编写表单 1.5、编写controller层 2、多文件上传 2.1、编写form表单 2.2、编写controller层 2.3、测试 三、文件下载 四、JREBEL使用 1、下载注册 2、离线设置 一…...

数据结构 第二章作业 线性表 西安石油大学

在顺序表中插入和删除一个结点需平均移动多少个结点?具体的移动次数取决于 哪两个因素? 在顺序表中插入和删除一个结点时,平均移动的结点数量取决于两个因素:插入/删除位置和当前顺序表的长度。 插入/删除位置:如果要…...

vue.mixin全局混合选项

在Vue.js中,Vue.mixin 是一个用来全局混合(mixin)选项的方法。它允许你在多个组件中共享相同的选项,例如数据、方法、生命周期钩子等。这可以用来在组件之间重复使用一些逻辑或共享一些通用的功能 Vue.mixin({// 在这里定义混合的选项data() {return {s…...

VMware Fusion 13+Ubuntu ARM Server 22.04.3在M2芯片的Mac上共享文件夹

因为Server版没有桌面,VMware Tools不能直接装,导致没办法共享文件。 Ubuntu中的包如果需要更新,先执行下面的步骤 sudo apt update 再执行 sudo apt upgrade 不需要更新的话,直接执行下面的步骤 先把open-vm-tools卸载了 …...

PostgreSQL serial类型

serial类型和序列 postgresql序列号(SERIAL)类型包括 smallserial(smallint,short),serial(int)bigserial(bigint,long long int) 不管是smallserial,serial还是bigserial,其范围都是(1,9223372036854775807)&#…...

[创业之路-76] - 创业公司如何在长期坚持中顺势而为?诚迈科技参观交流有感

目录 一、创业环境 1.1. VUCA乌卡时代:易变、复杂、不确定性、模糊的时代 1.2. 中国用了四十年的时间完成了三次工业革命:机械化、电气化、数字化 1.3. 中国正在经历着第四次工业革命:智能化、生态化、拟人化 1.4 国产替代:国…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!

本文介绍了一种名为AnomalyAny的创新框架&#xff0c;该方法利用Stable Diffusion的强大生成能力&#xff0c;仅需单个正常样本和文本描述&#xff0c;即可生成逼真且多样化的异常样本&#xff0c;有效解决了视觉异常检测中异常样本稀缺的难题&#xff0c;为工业质检、医疗影像…...

Docker拉取MySQL后数据库连接失败的解决方案

在使用Docker部署MySQL时&#xff0c;拉取并启动容器后&#xff0c;有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致&#xff0c;包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因&#xff0c;并提供解决方案。 一、确认MySQL容器的运行状态 …...