所向披靡の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 …

【Python进阶】 类的系统知识总结 | 特殊变量方法 单双下划线、继承、多态、装饰器

之前在C中学过一些类与对象的知识&#xff0c;Python也同样是面向对象的&#xff0c;因而也有类与对象 浅浅总结一下 总结Python中关于类的知识 文章目录 1 类的基本定义和访问2 特殊变量&#xff08;属性/方法&#xff09;2.1 双下划线开头结尾——特殊方法2.1.1 初始化方法…

Git与GitHub交互

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

web server apache tomcat11-34-Ahead of Time compilation support

前言 整理这个官方翻译的系列&#xff0c;原因是网上大部分的 tomcat 版本比较旧&#xff0c;此版本为 v11 最新的版本。 开源项目 从零手写实现 tomcat minicat 别称【嗅虎】心有猛虎&#xff0c;轻嗅蔷薇。 系列文章 web server apache tomcat11-01-官方文档入门介绍 web…

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

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

超越视觉极限:深度学习图像超分辨率算法清单【第四部分】

超越视觉极限&#xff1a;深度学习图像超分辨率算法清单【第四部分】 简介2019年 - SAN (Second-Order Attention Network)2019年 - IMDN (Information Multi-Distillation Network)2020年 - SwinIR (Swin Transformer for Image Restoration)2021年 - Real-ESRGAN (Real-World…

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

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

大数据技术概述_2.大数据面临的5个方面的挑战

1. 大数据面临着5个主要问题 2012年冬季&#xff0c;来自IBM、微软、谷歌、HP、MIT、斯坦福、加州大学伯克利分校、UIUC等产业界和学术界的数据库领域专家通过在线的方式共同发布了一个关于大数据的白皮书。该白皮书首先指出大数据面临着5个主要问题&#xff0c;分别是异构性&a…

环境搭建 docker-compose

systemctl restart network docker-compose 单独执行一个文件 docker-compose -f version: 3services:nacos-standalone:image: nacos/nacos-server:v2.3.1 container_name: nacos-standaloneenvironment:- PREFER_HOST_MODEhostname- MODEstandalone- NACOS_AUTH_IDENTITY_…

阿里云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命令查看磁盘使用情况 发现磁盘…

C语言:初学者和专家的分水岭

C语言&#xff1a;初学者和专家的分水岭 C语言作为一门古老而强大的编程语言&#xff0c;被认为是菜鸟和大神之间的分水岭。在编程领域&#xff0c;C语言不仅是初学者学习的重要起点&#xff0c;也是专家深入研究和高级编程的基础。本文将通过具体实例来说明C语言在不同级别开发…

【leetcode】链表排序题目总结

21. 合并两个有序链表 递归法 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : va…

怎么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] …