1. 自动化构建:make / Makefile
make命令和Makefile文件搭配使用共同完成项目的自动化构建
1.1 make命令
手动gcc编译的痛点:重复劳动,命令长,文件多
有了Makefile,执行make即可自动化编译 / 支持在文件修改后重新编译
1.2 Makefile文件
1.2.1 介绍
基本Makefile文件包含:
- 依赖关系
- 依赖方法
- 项目清理
举个例子:
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 - 清理
clean:make clean触发
1.2.2 伪目标声明:.PHONY
文件 = 内容 + 属性,属性通过stat 文件查看,包括:
Access:文件最近一次被访问的时间Modify:内容修改,更新时间Change:属性变更,更新时间

改内容(M)一定会改属性(C),改属性(C)不一定会改内容(M)
make判断文件是否更新的依据:.c和.exe的Modify时间先后
(why?因为将内容更新作为判断依据最合适,最准确
如图:

make本身不支持重复编译:

伪目标的作用:
- 让
make忽略源文件和可执行文件之间的时间对比,强制执行(make视角:目标名=文件名 - 排除和动作同名的文件干扰(
clean - 方便阅读:列表中的声明为动作,并非文件
对比:若文件夹中有同名clean文件
- clean在
.PHONY列表中:无限制强制执行

- 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;
}
运行效果:

感谢阅读,我们下篇见。

1347

被折叠的 条评论
为什么被折叠?



