[Linux系统] 自动化构建make / Makefile | 进度条

1. 自动化构建:make / Makefile

make命令和Makefile文件搭配使用共同完成项目的自动化构建

1.1 make命令

手动gcc编译的痛点:重复劳动,命令长,文件多
有了Makefile,执行make即可自动化编译 / 支持在文件修改后重新编译

1.2 Makefile文件

1.2.1 介绍

基本Makefile文件包含:

  1. 依赖关系
  2. 依赖方法
  3. 项目清理

举个例子:

code:code.c //依赖关系
	gcc -o code.exe code.c //依赖方法

.PHONY:clean //伪目标
clean: //项目清理
	rm -rf code
  • 依赖关系:proc.o依赖于proc.exe
  • 对应依赖方法:(Tab开头)gcc -o code.exe code.c
  • 清理cleanmake clean触发

1.2.2 伪目标声明:.PHONY

文件 = 内容 + 属性,属性通过stat 文件查看,包括:

  1. Access:文件最近一次被访问的时间
  2. Modify:内容修改,更新时间
  3. Change:属性变更,更新时间

在这里插入图片描述
改内容(M)一定会改属性(C),改属性(C)不一定会改内容(M)
make判断文件是否更新的依据:.c和.exe的Modify时间先后
(why?因为将内容更新作为判断依据最合适,最准确
如图:
在这里插入图片描述
make本身不支持重复编译:
在这里插入图片描述
伪目标的作用:

  1. make忽略源文件和可执行文件之间的时间对比,强制执行(make视角:目标名=文件名
  2. 排除和动作同名的文件干扰(clean
  3. 方便阅读:列表中的声明为动作,并非文件

对比:若文件夹中有同名clean文件

  1. clean在.PHONY列表中:无限制强制执行
    在这里插入图片描述
  2. clean不在.PHONY列表:被识别为文件
    在这里插入图片描述

补充touch可以刷新文件的A,C,M时间,不修改内容
在这里插入图片描述

1.2.3 依赖推导

make会层层深入找文件的依赖关系:

  • 线性推导链类似结构:make从目标proc出发,沿依赖链层层深入(proc.o → proc.s → proc.i → proc.c,相当于入栈);到达最底层的proc.c后,开始逐层返回、依次执行命令生成 proc.i → proc.s → proc.o → proc(相当于出栈)
  • 非线性:深度优先后序遍历
proc:proc.o
	gcc proc.o -o proc
proc.o:proc.s
	gcc -c  proc.s -o proc.o
proc.s:proc.i
	gcc -S proc.i -o proc.s
proc.i:proc.c
	gcc -E proc.c -o proc.i

.PHONY:clean
clean:
	rm -f *.i *.s *.o proc

1.2.4 拓展语法

//定义变量
SRC=$(wildcard *.c) //wildcard函数,获取所有.c文件名
OBJ=$(SRC:.c=.o) //将SRC的所有.c替换为同名.o形成目标文件列表
BIN=processbar

//$@:目标文件名;$^:依赖文件列表
$(BIN):$(OBJ)
	gcc -o $@ $^ 


%.o:%.c //%.c:展开当前目录下所有.c;%.o:同时展开同名.o
	gcc -c $< //$<:对展开的依赖.c文件逐个交给gcc

.PHONY:
clean:
	rm -f $(BIN) $(OBJ)

1.3 常见问题

  • gcc -o参数顺序写反,会毁掉源文件->正确写法:源文件在前,-o输出在后
  • make本职是保证目标文件最新
  • Makefile依赖方法需Tab,不可用空格

2. 模拟实现:进度条

2.1 前置知识

回车(\r)!= 换行(\n):不刷新缓存区vs刷新 / 回到行首vs跳至下一行在这里插入图片描述

2.2 代码片段

process.h

#include<stdio.h>

void process_v1();

void FlushProcess(double total, double current);

process.c

#include "process.h"
#include<string.h>
#include<unistd.h>

#define NUM 101
#define STYLE '#'

void FlushProcess(double total, double current) //一次打印
{
    char buffer[NUM];
    memset(buffer, 0,sizeof(buffer));
    const char* lable = "|/-\\";
    int len = strlen(lable);

    static int cnt = 0; //lable下标:静态是为了能不间断旋转
    int num = (int)(current * 100) / total; //下载进度(需要加载多少个#
    for(int i=0; i<num; ++i)
    {
        buffer[i] = STYLE;
    }

    double rate = current / total; //下载进度(比率
    cnt %= len;
    printf("[%-100s][%.1f%%][%c]\r", buffer, rate * 100, lable[cnt]);
    ++cnt;

    fflush(stdout);
}

//无法使用,伪进度条
void process_v1()
{
    char buffer[NUM];
    const char* lable = "|/-\\";
    int len = strlen(lable);
    memset(buffer, 0, sizeof(buffer));

    int cnt = 0;
    while(cnt <= 100)
    {
        printf("[%-100s][%d%%][%c]\r", buffer, cnt, lable[cnt%len]);
        buffer[cnt] = STYLE;

        fflush(stdout);
        usleep(50000);
        ++cnt;
    }

    printf("\n");
}

main.c

#include"process.h"
#include<unistd.h>

double total = 1024.0;
double speed = 1.0;

typedef void (*callback_t)(double total, double current);

void Download(callback_t cb)
{
    double current = 0;
    while(current <= total)
    {
        cb(total, current);

        usleep(3000);
        current += speed;
    }

    printf("\ndownload %.2lfMB Done\n", current);
}

void Upload(callback_t cb)
{
    double current = 0;                          
    while(current <= total)                      
    {                                            
        cb(total, current);                      
                                                 
        usleep(3000);                            
        current += speed;                        
    }                                            
                                                 
    printf("\nupload %.2lfMB Done\n", current);
}


int main()
{
    Download(FlushProcess);
    Download(FlushProcess);
    Download(FlushProcess);

    Upload(FlushProcess);
    Upload(FlushProcess);
    Upload(FlushProcess);

    return 0;
}

运行效果:
在这里插入图片描述

感谢阅读,我们下篇见。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值