Linux基础-Makefile的编写、以及编写第一个Linux程序:进度条(模拟在 方便下载的同时,更新图形化界面)
目录
一、Linux项目自动化构建工具-make/Makefile
编辑
背景:
makefile小技巧:
二、Linux第一个小程序-进度条
先导:
1.如何利用/r,fflush(stdout)来实现我们想要的效果;
2.写一个倒计时:
进度条:
version1:一个普通的进度条
version2:具体的应用场景,模拟下载软件
version3:在未来,方便下载的同时,更新图形化界面
代码:version3:
processbar.c:
processbar.h:
Main.c:
进度条完整代码在文章末尾
一、Linux项目自动化构建工具-make/Makefile
如图:让我们简单的来看一下makefile具有什么功能
你可以随意创建一个可运行的代码
在Makefile中
mytest:test.c gcc -o mytest test.c .PHONY:clean clean: rm -f mytest
然后:
makefile是一个文件,make是一个命令。
背景:
1.会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力
2.一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作
3.makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
4.make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
5.make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
依赖关系:
$表示:取内容
code.exe依赖于code.c
$@---目标文件
$^----整个依赖文件列表
注意:在makefile内的注释是#
如图:我们在makefile中这样写到
code.exe:code.o gcc code.o -o code.exe code.o:code.s gcc -c code.s -o code.o code.s:code.i gcc -S code.i -o code.s code.i:code.c gcc -E code.c -o code.i .PHONY:clean clean: rm -f code.i code.s code.o code.exe
makefile从上往下识别,而识别到code.o时,code.o并不存在,就不会执行该命令,继续往下识别,知道识别到code.c时,执行code.c的命令,再倒序执行。
一定要把最终需形成的文件放置开头
makefile小技巧:
makefile支持变量:
在执行程序时,隐藏命令
在使用makefile时,依赖方法只能有一行吗?可以有多行
我们不想显示这些命令:
二、Linux第一个小程序-进度条
\r&&\n
回车概念
换行概念
老式打字机的例子我们键盘上的Enter键就相当于回车+换行 \r\n
先导:
1.如何利用/r,fflush(stdout)来实现我们想要的效果;
如图:我在test.c和makefile文件中写入这样的代码
打印后程序休眠3s,结束程序
test.c:
#include<stdio.h> int main() { printf("hello zz,hello world...\n"); return 0; }
makefile:
bin=test.exe src=test.c $(bin):$(src) @gcc -o $@ $^ @echo "complier &(src) to &(bin)..." .PHONY:clean clean: @rm -f $(bin) @echo "clean project..."
同上:
3s后再打印,程序退出同时,打印。(未打印时,不代表程序没执行,只是放于缓冲区了)
提问:printf和sleep哪个函数先运行?printf先运行,由于执行代码是从上至下。
一般只有缓冲区满的时候,程序结束的时候,才会刷新缓冲区,因此在这里我们用到fflush函数强制刷新。
查阅手册:
修改代码后:
2.写一个倒计时:
在test.c中写到:
#include<stdio.h> #include<unistd.h> int main() { int cnt = 10; while(cnt >= 0) { printf("%d\r",cnt); fflush(stdout); --cnt; sleep(1); } printf("\n"); return 0; }
实际上当我们运行程序时,会出现一个问题,明明打印的是10 - 0,但是,却变成从10、90、80....
这是因为,打印在显示器上的都是字符,当10时是两个字符,而当变为9后,只有一个字符,0无法被覆盖,则会一直被打印,解决办法:%2d
执行这个代码后,就会直接覆盖两个字符。
#include<stdio.h> #include<unistd.h> int main() { int cnt = 10; while(cnt >= 0) { printf("倒计时: %2d\r",cnt); fflush(stdout); --cnt; sleep(1); } printf("\n"); return 0; }
进度条:
version1:一个普通的进度条
processbar--processbar.c--processbar.h--Main.c
然后在makefile中写到:
processbar:Main.c processbar.c gcc -o $@ $^ .PHONY:clean clean: rm -f processbar
在processbar.c--processbar.h--Main.c分别写到:
processbar.c--processbar.h--Main.c
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][%2d%%][%c]\r",bar,cnt,lable[cnt%len]); fllush(stdout); bar[cnt++] = Style; usleep(50000); } printf("\n"); }
usleep,相当于原来sleep的10^-6,因此在这里代表将原本的100s缩短为5s完成
之后会输出这样的结果:
当然这样还不够完美:
version2:具体的应用场景,模拟下载软件
在Main.c
#include"processbar.h" #include<unistd.h> //download void download() { double filesize = 100*1024*1024;//100M double current = 0.0; double bandwidth = 1024*1024*1.0; printf("download begin,current: %lf\n",current); while(current <= filesize) { Procbar(filesize,current); //从网络中获取数据 current += bandwidth; usleep(50000); } printf("\ndownload done, filesize:%lf\n",filesize); } int main() { //Procbar(100.0,56.9); //Procbar(100.0,1.0); //Procbar(100.0,99.9); //Procbar(100.0,100); download(); return 0; }
在processbar.c中:
#include"processbar.h" #include<string.h> #include<unistd.h> #define Length 101 #define Style '#' 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; } printf("\n"); }
这样却是一行一行的输出:
其实是因为
最后:
更优processbar.c代码:
#include"processbar.h" #include<string.h> #include<unistd.h> #define Length 101 #define Style '#' 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][%.1f%][%c]\r",bar,rate,lable[cnt%len]); // fflush(stdout); bar[cnt++] = Style; } printf("[%-100s][%.1f%][%c]\r",bar,rate,lable[cnt%len]); fflush(stdout); }
version3:在未来,方便下载的同时,更新图形化界面
Main.c:
#include"processbar.h" #include<unistd.h> //download void download(callback_t cb) { double filesize = 100*1024*1024;//100M double current = 0.0; double bandwidth = 1024*1024*1.0; printf("download begin,current: %lf\n",current); while(current <= filesize) { cb(filesize,current); //从网络中获取数据 current += bandwidth; usleep(50000); } printf("\ndownload done, filesize:%lf\n",filesize); } int main() { //Procbar(100.0,56.9); //Procbar(100.0,1.0); //Procbar(100.0,99.9); //Procbar(100.0,100); download(Procbar); return 0; }
processbar.h:
#pragma once #include<stdio.h> #include<unistd.h> //void Procbar(); typedef void(*callback_t)(double ,double ); void Procbar(double total,double current);
再更新
#include"processbar.h" #include<unistd.h> double bandwidth = 1024*1024*1.0; //download void download(double filesize,callback_t cb) { //double filesize = 100*1024*1024;//100M double current = 0.0; printf("download begin,current: %lf\n",current); while(current <= filesize) { cb(filesize,current); //从网络中获取数据 current += bandwidth; usleep(50000); } printf("\ndownload done, filesize:%lf\n",filesize); } int main() { //Procbar(100.0,56.9); //Procbar(100.0,1.0); //Procbar(100.0,99.9); //Procbar(100.0,100); download(100*1024*1024,Procbar); download(10*1024*1024,Procbar); download(99*1024*1024,Procbar); download(900*1024*1024,Procbar); return 0; }
最后:
代码:version3:
processbar.c:
#include"processbar.h"
#include<string.h>
#include<unistd.h>
#define Length 101
#define Style '#'
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][%.1f%][%c]\r",bar,rate,lable[cnt%len]);
// fflush(stdout);
bar[cnt++] = Style;
}
printf("[%-100s][%.1f%][%c]\r",bar,rate,lable[cnt%len]);
fflush(stdout);
}
processbar.h:
#pragma once
#include<stdio.h>
#include<unistd.h>
//void Procbar();
typedef void(*callback_t)(double ,double );
void Procbar(double total,double current);
Main.c:
#include"processbar.h"
#include<unistd.h>
double bandwidth = 1024*1024*1.0;
//download
void download(double filesize,callback_t cb)
{
//double filesize = 100*1024*1024;//100M
double current = 0.0;
printf("download begin,current: %lf\n",current);
while(current <= filesize)
{
cb(filesize,current);
//从网络中获取数据
current += bandwidth;
usleep(50000);
}
printf("\ndownload done, filesize:%lf\n",filesize);
}
int main()
{
//Procbar(100.0,56.9);
//Procbar(100.0,1.0);
//Procbar(100.0,99.9);
//Procbar(100.0,100);
download(100*1024*1024,Procbar);
download(10*1024*1024,Procbar);
download(99*1024*1024,Procbar);
download(900*1024*1024,Procbar);
return 0;
}
结语:
随着这篇关于题目解析的博客接近尾声,我衷心希望我所分享的内容能为你带来一些启发和帮助。学习和理解的过程往往充满挑战,但正是这些挑战让我们不断成长和进步。我在准备这篇文章时,也深刻体会到了学习与分享的乐趣。
在此,我要特别感谢每一位阅读到这里的你。是你的关注和支持,给予了我持续写作和分享的动力。我深知,无论我在某个领域有多少见解,都离不开大家的鼓励与指正。因此,如果你在阅读过程中有任何疑问、建议或是发现了文章中的不足之处,都欢迎你慷慨赐教。 你的每一条反馈都是我前进路上的宝贵财富。同时,我也非常期待能够得到你的点赞、收藏,关注这将是对我莫大的支持和鼓励。当然,我更期待的是能够持续为你带来有价值的内容,让我们在知识的道路上共同前行