所向披靡のmakefile

在VS里敲代码,只需要Fn+F5就可以直接运行勒,在Linux下敲代码却要即敲命令还要用编辑器还要用编译器,那在Linux下有没有能帮我们进行自动化组建的工具呢?

当然有,超级巨星:makefile!!!!

大致认识

首先创建一个叫makefile的文件(首字母大小写都可以哦)

touch makefile

21348046d1db455c9b9ca28a2721269f.png

用vim编辑一下这个文件:

mytest:test.cgcc -o mytest test.c

这个的含义是,构建一个叫mytest的文件,这个文件依赖的是test.c 

 d30fc6c477574ed39fceaec7a2b2a0f9.png

 make一下就自动编译好啦:

2d721f6e88c644288371f747b07df086.png 继续编辑Makefile,清理生成的临时文件:

.PHONY:clean 
clean:
rm -f mytest

417b99b62d8f4719901ec50e14b9cfd5.png

这样就清理掉了:

b45d00e8297a46fd94abb6dbb421e44b.png

依赖文件列表的文件按照空格为分割:

test.c test1.c test2.c

依赖文件前必须是Tab键 

关系就是,最终的文件按照依赖文件列表用依赖方法来形成可执行程序(make会根据makefile的内容,完成编译、清理工作)

我们应该怎么理解依赖关系和依赖方法呢?

来听个小故事:墨墨酱是一名大学生,到了月末,墨墨酱摸摸自己的口袋,居然只剩十块钱勒(实在不行啃树皮吃吧,芝士就是力量),于是墨墨酱开始紧急避险,拨打电话号码,电话接通后,刚说了一声“爸”,电话就匆匆挂(墨墨酱在告知她上学需要依赖父母,虽然要钱没要成,这个过程叫表明依赖关系),但是只表明依赖关系是肯定要不到钱钱的!还要表明你的诉求:想要生活费(依赖方法)

运行原理

make是一个命令,makefile是一个文件

make的运行规则是:从上到下扫描,默认形成第一个目标文件(在默认情况下只执行一对依赖关系和依赖方法)

.PHONY后面修饰的方法总是被执行(在Linux中,如果编译的已经是最新文件,就会拒绝你的命令,因为已经是最新的了,没必要再编一遍)

e4a2a25f74804c3bbd8e356c345b18d6.png

我们希望清理总是被执行,所以上面那样写  

那么为什么makefile对最新的可执行程序,默认不想重新形成呢?

因为有很多程序运行起来肯定不止一个源文件,如果只改动了某个源文件的一小部分,就要把所有的程序重新编译,则效率很低(所以为了提高编译效率就这样做啦)

那makefile是怎么做到的呢?

为什么makefile知道我的程序被编译了呢?

因为会对比时间呀

还要从文件的属性谈起,还记得那三个时间吗?

f873e3c857034fa7a6086e1b9cba974d.png

常规开发过程:

编写源代码--->编译(对比可执行文件的最近修改时间和源文件的最近修改时间谁更新)

touch同名文件可修改对应时间,有的时间修改的规则不一样,可能重新构建一下就能正常运行了

2da578545d184ae29beefcbb13a0493a.png

在makefile里会自动进行目标文件替换,来认识一下makefile里面的内置符号:

$:取内容

@:目标文件   

^:依赖文件列表

在makefile里注释用#

0aebe2e11eb3417482866812db91c316.png

每组依赖关系匹配着对应的依赖方法 ,上面的东西写全了之后是这样的: 

code.exe:code.ogcc code.o -o code.exe
code.o:code.sgcc -c code.s -o code.o
code.s:code.igcc -S code.i -o code.s
code.i:code.cgcc -E code.c -o code.i

763c1a767fca49bc96b2c95a803e6b51.png

添加上清理的东西:

.PHONY:clean
clean:rm -f code.i code.s code.o code.exe

85287f57e11b4c4baf61762f10a0f5dc.png

自己构建的makefile就是好用:

002538e5c07840deb4bb761ba9e22fa3.png以上内容总结一下就是:makefile/make会自动根据文件中的依赖关系,进行自动推导(入栈入栈入栈,出栈出栈出栈),帮助我们执行所有相关的依赖方法 

tips:makefile支持乱序,但要把最终要形成的文件放在最前面

在makefile中支持定义变量,格式是这样的:

变量名=变量内容

 于是上面的内容改写一下:

bin=code.exe
src=code.c$(bin):$(src)gcc -o $@ $^
.PHONY:clean
clean:rm -f $(bin)

fda6ce5350db4f6695e079171c226bec.png

这个就跟宏定义差不多,在改文件的时候可以一键替换,而且以后很多地方会用到比较方便

如果不想让它打印命令就可以在前面加个@

就像这样:

bin = test.exe
src = test.c
$(bin) :$(src)@gcc -o $@ $^.PHONY:clean
clean :@rm -f $(bin)

40e5927a7e6e490ca117010fcceeaf5a.png

如果想要其打印提示信息的话就是:

bin = test.exe
src = test.c
$(bin) :$(src)@gcc -o $@ $^@echo "compiled $(src) to $(bin)..."
.PHONY:clean
clean :@rm -f $(bin)@echo "clean project"

901a82cdf19b4f5ba86cc0935a52c014.png

未知进度条 

然后来隆重介绍下Linux的进度条小程序,首先介绍两个前置知识(超绝小技巧):

回车和换行

回车和换行是什么关系呢?

我们在C中学习的\n是什么意思捏?当然是回车换行!

但是你看,(超绝老式键盘已经在提示你了)它是这样的:

3690fb6760fd46e2b52ed2f6bc715da3.jpeg

它长得像个楼梯:这代表先换行再回车呀,这是两个动作

红色的是超绝换行,蓝色的是在打字,打字之后可以拨回来,那就是超绝回车

只想回车是\r,当\r存在时(也就是\r\n的时候,\n才表示换行)

缓冲区

缓冲区是什么在哪里怎么用?

缓冲区其实就是一块内存空间

printf中的内容拷贝到缓冲区,再将相应的数据刷新到显示器上

程序要结束时一般要自动强制冲刷缓冲区,而\n也可以刷新缓冲区(行刷新),缓冲区满了也会进行刷新

请看码:

#include <stdio.h>
#include<unistd.h>
int main()
{printf("hello world!!!\n");sleep(3);return 0;
}
#include <stdio.h>
#include<unistd.h>
int main()
{printf("hello world!!!");sleep(3);return 0;
}

猜猜这两段输出都是什么? 

 7b5acd9400bb4fde9d03cb48ca6295f5.jpeg

让我来公布下正确答案:

带\n的那个肯定是先输出再睡呀

不带的那个是先睡后输出

efdba24790fa40e2a70f9823480c90db.jpeg

那这样的带不带\n的差别是什么呢,是不是函数运行的先后不同呢?又是哪个函数先运行呢?

首先明确一点:程序永远都是从上往下执行

那也就相当于执行sleep的时候早就将printf执行完了

既然printf都给我打印字符串了,那它放在哪了呢?

凭什么不让我看???

这个消失的它(bushi)是被放在了缓冲区,程序要结束时一般要自动强制冲刷缓冲区,所以在第二个例子中是先睡觉后打印(由于缓冲区没有被刷新,所以先睡,程序结束之后在显示器上显示出来)而在第一个例子中则是有\n缓冲区会自动刷新,所以是先输出再睡

至于为什么要有缓冲区这样一个设定捏?

我给你输啥你就显示啥得了呗,非要这样拖着我一下,嗯?

缓冲区的存在是为了提高效率,向外刷新的次数越少,那效率就会越高(这就跟快递小哥送快递一样,肯定是一坨一坨送快呀,总不能一颗一颗送吧)

要为外卖行业添砖JAVA啊!看我超绝锻炼车技!我要让你们都吃上超绝热乎饭!

这就设计的很绝呀,在考虑效率的同事顾及用户的需求,直接从记忆成本变成理解成本了

“老师我想回去覆盖”

“害砸你实现倒计时啦!”

#include<stdio.h>
#include<unistd.h>
int main()
{int cnt = 9;while (cnt >= 0){printf("倒计时:%d\r",cnt);fflush(stdout);cnt--;sleep(1);}return 0;
}
fflush

fflush是什么?

布吉岛,man一下:

111abd88cdce4286bbc66ba2ab882c0a.png fflush是把特定文件流中的数据刷新

int fflush(FILE *stream);

这句里面的超绝FILE*是什么意思?

很简单:Linux的设计理念:一切皆文件,那我拿显示器当文件不过分吧?

其实C程序在启动的时候会默认启动三个输入输出流,他们分别是:

ae1c00a5a7d34edcb91d8c5cc41ab7ce.png

extern FILE* stdin;           //键盘
extern FILE* stdout;          //显示器
extern FILE* stdin;           //显示器

 一般打印出的消息通过stdout打印到显示器上,那为什么程序启动默认帮我打开这三个流呢(标准输入,标准输出,标准错误),首先,打开文件是编译器和系统帮忙做的,在源代码编译时添加了一部分代码,打开键盘显示器上的代码,计算机的作用是计算,要让用户把自己的数据输入进来,经过计算后显示到显示器上让人看到结果(方便用户输入输出)

为什么要进行行刷新呢?

肯定是因为方便啊,就这样

如果这样捏?

#include<stdio.h>
#include<unistd.h>
int main()
{int cnt = 10;while (cnt >= 0){printf("倒计时:%d\r",cnt);fflush(stdout);cnt--;sleep(1);}return 0;
}

由于在显示器(字符设备)上显示的东西都是字符,所以由于超绝字符显示,就有一只超级棒的0挥之不去了,显示出来是10,90,80,70......

如果想要其正常显示,就可以这样:

#include<stdio.h>
#include<unistd.h>
int main()
{int cnt = 10;while (cnt >= 0){printf("倒计时:%2d\r",cnt);fflush(stdout);cnt--;sleep(1);}return 0;
}

 stdin                  超绝键盘

stdout,stderr    超绝显示器

同样的数据给给给,等于两份

不回显:键盘和你交互了,没把数据给显示器

超绝进度条

搞一些东西:

mkdir proccess
cd proccess
touch Processbar.c
touch Processbar.h
touch Main.c
touch makefile

e39eff9acfca4a64aff6b690045087bc.png

我们理想中的进度条是这样的:

 

能显示百分比,有进度

在实现的时候我们就用#来代表加载程度,末尾添加\0 

Processbar.h
#pragma once        //防止头文件重复展开
#include<stdio.h>
void ProcBar();
Processbar.c
#include"Processbar.h"
#include<string.h>
#include<unistd.h>
#define length 101
#define Style '#'const char* lable="|/-\\";
void ProcBar()
{char bar[length];memset(bar,'\0',sizeof(bar));int len=strlen(lable);int cnt=0;while(cnt<=100){printf("[%-100s][%3d%%][%c]\r",bar,cnt,lable[cnt%len]);fflush(stdout);bar[cnt++]=Style;usleep(20000);}printf("\n");return;
}
Main.c
#include"Processbar.h"
int main()
{ProcBar();return 0;
}
makefile
processbar:Main.c Processbar.cgcc -o $@ $^.PHONY:clean
clean:rm -f processbar

 以上就是进度条的简单实现了,但我们需要结合使用场景考虑,肯定不能是直接就单纯进度条,比如介绍一个下载的场景:

下载进度条

Processbar.h
#pragma once
#include<stdio.h>
void ProcBar(double total,double current);
Processbar.c
#include"Processbar.h"
#include<string.h>
#include<unistd.h>
#define length 101
#define Style '#'//version 2
const char* lable="|/-\\";
void ProcBar(double total,double current)
{char bar[length];memset(bar,'\0',sizeof(bar));int len=strlen(lable);int cnt=0;double rate=(current*100.0)/total;int loop_count =(int)rate;        while(cnt<=loop_count){printf("[%-100s][%.1lf%%][%c]\r",bar,rate,lable[cnt%len]);fflush(stdout);bar[cnt++]=Style;//usleep(20000);}return;
}
Main.c
#include"Processbar.h"
#include <unistd.h>
//download
void download()
{double filesize = 100*1024*1024*1.0;	//100Mdouble current=0.0;double bandwidth = 1024*1024*1.0;	//带宽:1Mprintf("download begin,current:%lf\n",current);	while(current <= filesize){ProcBar(filesize,current);	//根据具体数据判断进度条长度//从网络中获取数据current += bandwidth;usleep(100000);   }printf("\ndownload done,filesize: %lf\n",filesize);
}
int main()
{download();//ProcBar(100.0,56.9);//ProcBar(100.0,1.0);//ProcBar(100.0,99.9);//ProcBar(100.0,100);return 0;
}
makefile
processbar:Main.c Processbar.cgcc -o $@ $^.PHONY:clean
clean:rm -f processbar

多份文件进度条

Processbar.h
#pragma once
#include<stdio.h>
typedef void(*callback_t)(double,double);
void ProcBar(double total,double current);
Processbar.c
#include"Processbar.h"
#include<string.h>
#include<unistd.h>
#define length 101
#define style '#'//version 2
const char* lable="|/-\\";
void ProcBar(double total,double current)
{char bar[length];memset(bar,'\0',sizeof(bar));int len=strlen(lable);int cnt=0;double rate=(current*100.0)/total;int loop_count =(int)rate;while(cnt<=loop_count){// printf("[%-100s][%.1lf%%][%c]\r",bar,rate,lable[cnt%len]);// fflush(stdout);bar[cnt++]=Style;//usleep(20000);
}printf("[%-100s][%.1lf%%][%c]\r",bar,rate,lable[cnt%len]);fflush(stdout);return;
}
Main.c
#include"Processbar.h"
#include <unistd.h>
//download
double bandwidth = 1024*1024*1.0;       //带宽:1Mvoid download(double filesize,callback_t cb)
{double current=0.0;printf("download begin,current:%lf\n",current);while(current <= filesize){cb(filesize,current);   //根据具体数据判断进度条长度//从网络中获取数据usleep(100000);current += bandwidth;}printf("\ndownload done,filesize: %lf\n",filesize);
}
int main()
{download(100*1024*1024,ProcBar);download(1*1024*1024,ProcBar);download(200*1024*1024,ProcBar);download(400*1024*1024,ProcBar);download(1000*1024*1024,ProcBar);download(10*1024*1024,ProcBar);download(50*1024*1024,ProcBar);//ProcBar(100.0,56.9);//ProcBar(100.0,1.0);//ProcBar(100.0,99.9);//ProcBar(100.0,100);return 0;
}
makefile
processbar:Main.c Processbar.cgcc -o $@ $^.PHONY:clean
clean:rm -f processbar

超绝进度条告一段落,下次见~

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

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

相关文章

Dropout作为贝叶斯近似: 表示深度学习中的模型不确定性

摘要 深度学习工具在应用机器学习领域受到了极大的关注。然而&#xff0c;这些用于回归和分类的工具并没有捕捉到模型的不确定性。相比之下&#xff0c;贝叶斯模型提供了一个基于数学的框架来推理模型的不确定性&#xff0c;但通常会带来令人望而却步的计算成本。本文提出了一…

面试中算法(删去n个数字后的最小值)

有一个整数&#xff0c;从该整数中去掉n个数字&#xff0c;要求剩下的数字形成的新整数尽可能小。 分析&#xff1a;使用栈的特性&#xff0c;在遍历原整数的数字时&#xff0c;让所有数字一个一个入栈&#xff0c;当某个数字需要被删除时&#xff0c;&#xff08;即栈顶数字&g…

【记录】Python3| 将 PDF 转换成 HTML/XML(✅⭐PyMuPDF+tqdm)

本文将会被汇总至 【记录】Python3&#xff5c;2024年 PDF 转 XML 或 HTML 的第三方库的使用方式、测评过程以及对比结果&#xff08;汇总&#xff09;&#xff0c;更多其他工具请访问该文章查看。 文章目录 PyMuPDF 使用体验与评估1 安装指南2 测试代码3 测试结果3.1 转 HTML …

Git与GitHub交互

注册 https://github.com/ 本地库与远程库交互方式 创建本地库并提交文件 创建远程库 在本地库创建远程库地址别名 查看现有远程库地址的别名 git remote -v 创建远程库地址别名 git remote add [别名] [远程地址] 远程路地址位置 示例 成员1推送 git push [别名] [分支…

文心一言 VS 讯飞星火 VS chatgpt (254)-- 算法导论18.2 7题

七、假设磁盘硬件允许我们任意选择磁盘页面的大小&#xff0c;但读取磁盘页面的时间是 abt 其中 a 和 b 为规定的常数&#xff0c;t 为确定磁盘页大小后的 B 树的最小度数。请描述如何选择 t 以(近似地)最小化 B 树的查找时间。对 a5ms 和 b10ms &#xff0c;请给出 t 的一个最…

使用图网络和视频嵌入预测物理场

文章目录 一、说明二、为什么要预测&#xff1f;三、流体动力学模拟的可视化四、DeepMind神经网络建模五、图形编码六、图形处理器七、图形解码器八、具有不同弹簧常数的轨迹可视化九、预测的物理编码和推出轨迹 一、说明 这是一篇国外流体力学专家在可视化流体物理属性的设计…

阿里云CentOS 7.9 64位 Liunx 安装redis

具体的步骤如下&#xff1a; 添加 EPEL 仓库&#xff0c;因为 Redis 在标准的 CentOS 仓库中不可用&#xff1a; sudo yum install epel-release安装 Redis&#xff1a; sudo yum install redis启动 Redis 服务&#xff1a; sudo systemctl start redis如果你想让 Redis 在…

使用Vue3开发项目,搭建Vue cli3项目步骤

1.打开cmd &#xff0c;输入 vue create neoai遇到这样的问题 则需要升级一下电脑上 Vue Cli版本哈 升级完成之后 再次输入命令&#xff0c;创建vue3项目 vue create neoai安装完成后&#xff0c;输入 npm run serve 就可以运行项目啦~ 页面运行效果

【LLM 论文】OpenAI 基于对比学习微调 LLM 得到嵌入模型

论文&#xff1a;Text and Code Embeddings by Contrastive Pre-Training ⭐⭐⭐⭐ OpenAI 一、论文速读 这篇论文基于大型生成式 LLM 通过对比学习来微调得到一个高质量的 text 和 code 的 embedding 模型。 训练数据的格式&#xff1a;是一堆 ( x i , y i ) (x_i, y_i) (x…

上传文件至linux服务器失败

目录 前言异常排查使用df -h命令查看磁盘使用情况使用du -h --max-depth1命令查找占用空间最大的文件夹 原因解决补充&#xff1a;删除文件后&#xff0c;磁盘空间无法得到释放 前言 使用XFTP工具上传文件至CentOS服务器失败 异常 排查 使用df -h命令查看磁盘使用情况 发现磁盘…

怎么ai解答问题?这三个方法都可以

怎么ai解答问题&#xff1f;在数字化飞速发展的今天&#xff0c;人工智能&#xff08;AI&#xff09;技术已经渗透到我们生活的方方面面&#xff0c;尤其是在解答问题方面&#xff0c;AI展现出了令人瞩目的能力。那么&#xff0c;哪些软件可以利用AI技术解答问题呢&#xff1f;…

使用curl命令查看服务器端口开放情况

目录 1.ssh端口 22 2.mysql数据库端口 3306 3.web应用端口 &#xff08;Jellyfin 8082&#xff09; &#xff08;wordpress 8088&#xff09; &#xff08;tomcat 8080&#xff09; 4.不存在的端口 5.被防火墙阻挡的端口 1.ssh端口 22 curl -v 10.10.10.205:22 curl…

leetcode_47.全排列 II

47. 全排列 II 题目描述&#xff1a;给定一个可包含重复数字的序列 nums &#xff0c;按任意顺序 返回所有不重复的全排列。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,2] 输出&#xff1a; [[1,1,2],[1,2,1],[2,1,1]]示例 2&#xff1a; 输入&#xff1a;nums [1,2,3] …

了解你的构建:发布经理构建难点应对指南

在如今的计算机行业&#xff0c;发布经理的工作任重而道远。一方面他们必须紧跟日益攀升的行业标准&#xff0c;发布速度的极限不断突破&#xff0c;现在要求的速度在过去是远远无法想象的。另一方面&#xff0c;质量的门槛也在不断抬高。 我并非诟病软件更新换代过于迅速频繁…

揭秘数据可视化:五款利器助力决策

在当今这个数据驱动的时代&#xff0c;数据可视化已成为企业决策、数据分析不可或缺的一部分。通过直观、生动的图形、图像&#xff0c;数据可视化能够更快速、更准确地传达信息&#xff0c;帮助企业洞察数据背后的价值。本文将为您介绍几款优秀的数据可视化工具。 一、山海鲸…

Backblaze发布2024 Q1硬盘故障质量报告-1

作为一家在2021年在美国纳斯达克上市的云端备份公司&#xff0c;Backblaze一直保持着对外定期发布HDD和SSD的故障率稳定性质量报告&#xff0c;给大家提供了一份真实应用场景下的稳定性分析参考数据。 截至2024年第一季度末&#xff0c;Backblaze在其全球数据中心的云存储服务器…

弹性云服务器是什么,为何如此受欢迎

云计算作为当下炙手可热的技术领域&#xff0c;已然成为现代企业不可或缺的核心能力。云服务器作为云计算的基石之一&#xff0c;在这个数字化时代发挥着至关重要的作用。而弹性云服务器&#xff0c;作为云服务器的一种演进形式&#xff0c;更是备受瞩目。 弹性云服务器&#…

[笔记] Win11 Microsoft Store App 离线下载

微软应用商店无法下载或下载缓慢解决方法 在一些环境下 Microsoft Store 下载速度缓慢&#xff0c;或者需要账号登录才能安装的场景&#xff0c;可以通过找到对应的离线安装包的形式进行安装。 Micorsoft Store 中的离线安装包一般后缀为 AppxBundle 和 Appx。以 Ubuntu 为例…

如何根据IP获取国家省份城市名称PHP免费版

最近项目遇到需要根据IP获取用户国家功能需求&#xff0c;网上找了一下&#xff0c;很多API接口都需要付费&#xff0c;考虑为公司节约成本&#xff0c;就取找找有没有开源的 github 上面那个包含多种语言&#xff0c;下面这个只有php&#xff0c;用法很简单 $ip 114.114.114…

[蓝桥杯]真题讲解:班级活动(贪心)

[蓝桥杯]真题讲解&#xff1a;班级活动&#xff08;贪心&#xff09; 一、视频讲解二、正解代码1、C2、python33、Java 一、视频讲解 [蓝桥杯]真题讲解&#xff1a;班级活动&#xff08;贪心&#xff09; 二、正解代码 1、C #include<bits/stdc.h> using namespace st…