Linux—自动化构建工具make/makefile__倒计时or进度条

文章介绍了Linux项目中自动化构建工具make的使用,包括make的工作原理、依赖关系管理、清理可执行程序的方法,以及倒计时和进度条小程序的实现,涉及缓冲区、刷新机制和usleep/sleep的区别。
摘要由CSDN通过智能技术生成

目录

一.Linux项目自动化构建工具-make/Makefile

🎓make是如何工作的?

🎈依赖关系?

🎈依赖方法?

🎓打印出的makefile文件和make显示在显示器中的不一样?

🎓如何清理可执行程序?

🎓为什么只能make一次?

🎓特殊符号:

🚩显示依赖方法

🚩不显示依赖方法

二.倒计时小程序

👩🏾‍💻回车换行

👩🏾‍💻缓冲区

👩🏾‍💻强制刷新

👩🏾‍💻\r \n %md

三.Linux第一个小程序—进度条

💡基本思路及实现

💡增加百分比显示 

💡增加旋转光标

💡给进度条配色

💻优化


一.Linux项目自动化构建工具-make/Makefile

  • make:是一个指令
  • makefile:是一个当前目录下的文件


  • 🎓make是如何工作的?

make是如何工作的,在默认的方式下,也就是我们只输入make命令

make指令可以利用依赖关系,执行依赖方法中的内容,编译形成可执行文件

  • 🎈依赖关系?

  • 🎈依赖方法?

比如:你打电话给你爸要生活费,你不能和你室友的爸打电话要生活费,所以你和你爸是有依赖关系.

我要将mycode.c文件形成可执行程序文件mycode(mycode.c文件依赖的是mycode文件)

后者依赖前者,前者依赖于后者。 


  • 🎓打印出的makefile文件和make显示在显示器中的不一样?

make在扫描makefile 文件时,优先根据依赖关系表去找,后者在当前文件中存在,如果不存在就类似于递归式的先形成依赖文件,然后通过依赖关系,从上往下找到。mycode.c实际上是出口(栈的调用)

make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。

make会自动推导makefile中的依赖关系,推导过程是栈式结构


  • 🎓如何清理可执行程序?

make自上向下扫描makefile文件,一般都是将可执行程序放在前面,清理内容放在后面


  • 🎓为什么只能make一次?

  • 为什么不改自己的源代码,就不让你再次编译了?——【没有必要】
  • 为什么不能再次编译?——【主要提高编译效率】
  • 怎么做到的?——【一定是源文件形成可执行,先有源文件,才有可执行,一般而言,源文件的最近修改时间 比 可执行文件要老的

如果我们更改了源文件,历史上曾经还有可执行,那么源文件的最近修改时间,一定要比可执行程序要新。只需要比较,可执行程序的最近修改时间,和 源文件的最近修改时间

  • .exe 新于 .c 源文件是老的,不需要重新编译了
  • .exe 老于 .c 源文件是新的,需要重新编译了

一般而言,.exe==.c??? 一般不会。

  • 文件=文件内容+文件属性
  • modify对文件内容进行修改
  • change对文件属性进行修改
  • Access只读不修改
  • Access Modify Change(acm时间)

结论:make会根据源文件和目标文件的新旧,判定是否重新执行依赖关系进行编译(依赖关系不一定总是执行)

如果我让每一次可执行程序都是可以执行————.PHONY:伪目标

但是一般我们编译过的内容,就不需要再次重新编译了,所以一般不写

清理目标文件,需要每次都编译


🎓特殊符号:

  • 🚩显示依赖方法

  • 🚩不显示依赖方法


二.倒计时小程序

[##>                                                    ][40%][\]

👩🏾‍💻回车换行

  • \r表示回车,即将光标移动到当前行的起始位置
  • \n表示换行,即将光标向下移动一行

但是我们平时用的比如C语言打印的时候加一个\n换行

他不仅进行了换行并且光标也移到了起始位置。但是其实这是两个步骤,先移到下一行,再移动到起始位置。不过呢,在常见的计算机系统中,换行通常会伴随回车操作。


  • 我们看到这里就成功打印出来了hello world,并且进行了换行(且伴随了回车)。所以后面的命令提示符就打印到了下一行,并且在开头位置。

  • 那其实就是跟最后的\r有关系,printf打印的时候,前面的hello world都没问题,但是最后遇到\r(回车),就把光标移到了最左边起始位置。所以后面打印命令提示符的时候就把hello world覆盖掉了


👩🏾‍💻缓冲区

  • 缓冲区(Buffer)是计算机系统中用于临时存储数据的一块内存区域。它通常用于处理输入和输出操作,以提高效率和性能。

缓冲区相当于一个中间层,位于数据的来源和目的地之间。当进行输入或输出操作时,数据先暂时存储在缓冲区中,然后再批量地传输到目标位置或从源位置读取出来。这样可以减少对源位置或目标位置的直接读写次数,从而提高数据传输效率。

  • sleep()函数

头文件#include<unistd.h>,sleep() 函数用于在程序中暂停执行一段时间,sleep() 函数的参数是以秒为单位的等待时间。它的作用是让程序进入休眠状态,停止执行指定的时间间隔,然后再继续执行后续的代码。

  • 在Linux或UNIX系统中,可以包含<unistd.h> 头文件,使用 sleep() 函数。
  • 在Windows系统中,可以包含<windows.h> 头文件,使用 Sleep() 函数。

以上俩种情况,是先执行1还是先执行2呢?

  • 第一种带'\n',表示先打印,后进行休眠(因为我们使用了sleep)
  • 第二种不带'\n',表示先休眠,后进行打印,而且新的命令行直接跟在hello world后面,因为我们没有换行。

带\n的时候是先打印hello world,后休眠;而不带\n先休眠,后打印hello world。那这样的话,不带\n的时候,好像是先执行了sleep函数,然后才执行printf去打印。

当然不是的,我们知道程序默认是按照从上到下顺序执行的。所以肯定是先执行printf,再执行sleep,毋庸置疑。C语言是按照顺序执行的,(默认没有循环没有判断......)整个代码先执行printf再执行sleep所以顺序一定是1,2。


为什么我们看到的是两个程序打印的时机为什么不一样呢?

缓冲区相当于一个中间层,位于数据的来源和目的地之间。当进行输入或输出操作时,数据先暂时存储在缓冲区中,然后再批量地传输到目标位置或从源位置读取出来。不管我们有没有加\n,我们的hello world这个字符串都会被暂存到缓冲区里面。

原因其实是因为两个程序的缓冲区刷新的时机不同。

在大多数编程语言和操作系统中,缓冲区被用来暂时存储要输出或被读取的数据,直到达到一定条件后才会将其发送到目标位置(如屏幕、文件、网络等)。这个条件通常是缓冲区满了、遇到换行符、或者主动进行缓冲区刷新的操作。当程序结束时,通常会自动刷新输出缓冲区。这意味着在程序执行完成后,输出缓冲区中的所有数据将被写入到相应的输出设备(如终端或控制台)并在屏幕上显示出来。所以我们可以认为,遇到\n的时候就会触发缓冲区刷新操作。而程序结束也会刷新缓冲区。

  • 第一个程序我们加了\n,所以执行printf时遇到\n就会刷新缓冲区,那么hello world就直接显示到了显示器上。所以是先打印,后休眠。
  • 而第二个程序,没有\n,我们也没有手动刷新缓冲区,因为显示器是行刷新,\r也不能进行手动刷新,所以直到程序结束是刷新缓冲区,hello world 才会显示到显示器上。因此是先休眠,后打印。

👩🏾‍💻强制刷新

标准输入,标准输出(显示器,stdout),标准错误

fflush这个函数可以刷新缓冲区给,那这样就相当于我们提前刷新了一下缓冲区,这样休眠就在打印后面了,方便我们观察。

不加fflush(stdout)和加上fflush(stdout)打印一样,但是其实本质上面他们显示过程不一样

  • 不加fflush(stdout):调用了printf后,把0<x<10最后一次性进行了显示

  • 加了fflush(stdout):调用了printf后,把0<x<10放一个就输出一个,相当于着10个值从输出缓冲区一个一个蹦出来的。只是人眼看起来打印一样。


👩🏾‍💻\r \n %md

printf可以用格式控制串"%md"输出域宽为m的十进制整数(默认左对齐,-m则右对齐

\r是回车,回车是返回一行的头位置。再原来所在的位置倒计时,而不是一个位置跳到下一个位置

我们需要的倒计时是可以跳到头位置进行变化

 \r 回车符  %2d 右对齐   -%2d 左对齐


三.Linux第一个小程序—进度条

[##>                                  ][40%][\]

我们来写实现进度条的函数processbar

思路:一个大的【】,里面预留出来100个字符的空间,我们填充=,当然你也可以用其他的,1%就打印一个#,2%就两个,以此类推,后面可以显示一下具体是百分之几,随着#增加不断递增直到100%。

其实它大致的思路和上面的倒计时是一样的:就是不断的显示并覆盖之前的内容。

先创建这四个文件

makefile里面的内容:


💡基本思路及实现

  1. 首先我们可以先开一个数组,把进度条需要的100个字符的空间预留出来。那我们打印的时候可以直接打印=组成的字符串,那字符串的话就要再给\0开一个空间。
  2. 然后我们可以给bar数组全部初始化为\0,这样我们后续添加#就不用考虑\0的问题了。

3.然后我们循环打印并不断添加#就行了,当然我们这里还应该使用\r不断的回车,使每一次新打印的覆盖之前的,并且每次循环printf之后要使用fflush刷新缓冲区,这样才能每次循环都够打印出来内容,要不然程序结束之前一直留存在缓冲区。

 但是打印的结果从右向左打印 

 系统默认从右向左开始打#符号,所以在此之前用“-”号来表示就可以实现从左向右打印

sleep   usleep:

sleep(1)表示执行一个就是1s,如果执行到100%,那么就需要100s,那样是很慢的

sleep的参数是以为单位的,而usleep是以微秒为单位的。

我们可以设置成0.1秒休眠时间

  • 两个“休息函数”,一个是sleep(),另外一个是usleep();那么两者有什么区别呢?

两个函数的功能是一样的,区别在于“休息”时间的精确度,对于sleep()来说,最小单位为秒,也就是说使用sleep()的话最少只能休息1秒;而usleep()的最小单位为微秒

1秒=1000毫秒=1000000微秒),不难发现usleep()可以比sleep()“休息”更短的时间。

ps:usleep(100000)相当于sleep(0.1),所以完成100%,那么只需要10s即可完成。

注意在完成代码后,需要打印\n

否则进度条这一行显示完毕,新出现的命令行会把进度条的一部分覆盖掉。


💡增加百分比显示 

我们需要在[]右边加个百分比符号来表示进度

由于count是依次递增的,所以进度百分比显示可以利用count来计数

但这并没有显示%号,c语言后面加上%%号,就可以实现


💡增加旋转光标

可以通过循环显示这四个字符| / - \来模拟一个旋转的过程(注意\要用转义字符\\


💡给进度条配色

在C语言中,可以使用ANSI转义序列来输出不同的颜色。ANSI转义序列是一系列的字符组合,用于控制终端的文本样式和颜色。关于配色方案,网上可以找到很多相关的资料,大家有兴趣可以按照自己的喜好去配色,我这里简单演示一下:


💻优化

TOP表示最多元素100

主体符号是=,右侧符号是>


完整代码: 


因为我喜欢的东西都很贵,我想去的地方都很远,我爱的人超完美。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值