【Linux】Linux项目自动化构建工具——make/Makefile
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
我举报有人不学习
文章目录
一、makefile原理
1.
makefile文件既可以写成makefile也可以写成Makefile
2.
makefile文件中要写的是依赖关系和依赖方法例如生成的可执行程序mycode依赖的就是mycode.c源文件没有这个源文件就没有mycode这个可执行程序生成可执行程序的过程中又依赖方法gcc mycode.c -o mycode也就是需要gcc来编译链接生成可执行程序。
vim makefile
// 下面是makefile文件的内容
mycode:mycode.c
gcc mycode.c -o mycode
二、初步理解makefile的语法
第一行是依赖关系第二行必须以Tab键开头第二行写的是依赖方法
依赖关系可以为空
1 mycode:mycode.c
2 gcc mycode.c -o mycode
3
4 .PHONY:clean
5 clean:
6 rm -f mycode
1.
被.PHONY:关键字修饰的对象是一个伪目标该目标总是被执行的。
由于第一条依赖关系和依赖方法没有被.PHONY:修饰所以如果命令执行过且源文件没有被改动过的话make是不允许连续多次执行的但第二条依赖关系和依赖方法被.PHONY:修饰了所以它是可以多次执行的
2.
换句话说有了关键字.PHONY:修饰过后就不要通过对比源文件和可执行程序Modify时间来判断是否能够执行指令了不走这套规则我让你执行你就一直给我执行就OK了
1.gcc如何得知源文件不需要再编译了呢
Modify代表文件内容被修改的时间Change代表文件属性被修改的时间Access代表最后一次访问文件的时间值得注意的是文件大小也算文件的属性
1.
有时候访问文件的时间Access被更新的不是很灵敏以前老的操作系统内核对于这件事的原则就是只要你访问了就立马更新时间但现在的操作系统内核过一段时间之后才会更新我们的访问文件时间。
原因文件操作的时候改文件就一定会访问文件但访问文件不一定该文件所以访问文件的次数太多了要进行更多次的IO并且文件访问的时间基本没有人关心。
2.
一定先有源文件再有可执行程序所以源文件的Modify时间一定要比可执行程序的Modify时间更早所以gcc识别要不要重新编译比较的就是源文件和可执行程序的文件内容修改时间。如果可执行程序更早说明源文件被修改了那就需要重新编译如果源文件早说明可执行程序被修改过不需要重新编译。
当已经使用make指令过后无法继续使用时我们可以touch更新一下源文件的时间这个时候就又可以用make指令了这就证明了我们上面的结论。
touch mycode.c //touch后面跟上已存在的文件可以更新此文件的三个时间。
2.为什么执行的指令是make和make clean呢
make也可以跟上mycode使用make默认从上到下扫描文本makefile的时候第一个扫描到的目标文件可以省略名称使用例如直接使用make执行的就是makefile里面的第一个目标文件并且默认情况下makefile只形成一个目标文件也就是总目标文件只能有一个。
make mycode
make
make clean
三、makefile的推导规则
1 mycode:mycode.o
2 gcc mycode.o -o mycode
3 mycode.o:mycode.s
4 gcc -c mycode.s -o mycode.o
5 mycode.s:mycode.i
6 gcc -S mycode.i -o mycode.s
7 mycode.i:mycode.c
8 gcc -E mycode.c -o mycode.i
9
10 .PHONY:clean
11 clean:
12 rm -f mycode
1.
根据依赖关系列表make先找mycode发现没有那就去找mycode依赖的mycode.o结果发现也没有那就去找mycode.o依赖的mycode.s结果发现还是没有那就去找mycode.s依赖的mycode.i结果没找到那就去找mycode.i依赖的mycode.c结果找到了那就执行他们之间的依赖方法然后.i就有了那就再一点一点向上执行每条依赖方法
2.
这就是整个make的依赖性类似于堆栈结构make会一层又一层地去找文件的依赖关系直到最终编译出第一个目标文件。
四、Linux小程序—进度条
1.缓冲区概念
1.
如果加上\n那就会先显示you can see me然后停下来2秒钟如果没有\n的话那就会先停下来2秒然后才显示出you can see me。
2.
第一种拥有\n可以立即输出的原因是因为\n是行缓冲只要遇到\n就会立马将这一行的内容输出到显示器上面
3.
针对第二种没有\n的情况首先printf语句肯定是要先执行的唯一的可能性就是这个you can see me没有被立即显示出来等到走完sleep语句它才显示出来在未显示的这段时间里面you can see me一直被存储在行缓冲区里面
1 #include <stdio.h>
2 #include <unistd.h>
3
4 int main()
5 {
6 printf("you can see me ........\n");
7 sleep(2);
8 return 0;
9 }
// 可以利用fflush(stdout)语句来刷新缓冲区这样数据就会立马显示出来
1 #include <stdio.h>
2 #include <unistd.h>
3
4 int main()
5 {
6 printf("you can see me ........");
7 sleep(2);
8 return 0;
9 }
2.回车换行
理论上回车和换行不是一个概念换行是回到当前行的最开始换行是将光标挪到下一行相同的光标位置\r是回车\n是换行\r\n合起来我们称之为回车换行。
语言层面上\n就是回车换行因为编译器在内部对于\n做了特殊处理回车换行其实分成两步先换行再回车。
例如下面老式键盘的回车形状是先向下再向左的。
3.倒计时小程序
1.
显示器能够显示各种符号包括数字汉字字母等等这些都被计算机看作符号只不过人把它分为数字还是汉字字母等能够显示这么多符号是因为显示器面板上有各种像素点点亮对应显示器上的像素点就可以给人类显示出来各种各样的符号了并且凡是能够显示到显示器上的其实都是字符
2.
如果我们重新在第一个像素点输入8那么这个像素点就会重新显示8将9覆盖掉基于这样的原理我们就可以写一个倒计时小程序了。
1 #include <stdio.h>
2 #include <unistd.h>
3 int main()
4 {
5 int cnt=10;
6 while(cnt)
7 {
8 printf("剩余时间:%2d\r",cnt);
// 利用\r回车来实现同一个像素点显示多个数字这样看起来就像倒计时
9 fflush(stdout);
// 每次刷新一下缓冲区立马显示数据
10 cnt--;
11 sleep(1);
12 }
13 return 0;
14 }
4.进度条
gcc的-D选项可以帮助我们在命令行中完成某些变量的定义例如下面定义了进度条的样式为N=1时的样式。
ProcessOn文件依赖main.c和process.c源文件所以依赖关系和依赖方法如下
Makefile文件内容
1 ProcessOn:main.c process.c
2 gcc main.c process.c -o ProcessOn -D N=1
3
4 .PHONY:clean
5 clean:
6 rm -f ProcessOn
main.c文件内容
1 #include "process.h"
2
3 int main()
4 {
5 ProncessOn();
6 return 0;
7 }
process.h文件内容
1 #pragma once
2 #include <stdio.h>
3 #include <string.h>
4 #include <unistd.h>
5
6 #define NUM 101
7 #define S_NUM 5
8
9 extern void ProncessOn();
\033[42;34m 输出的内容 \033[0m这是内容的颜色控制
usleep代表的是微秒
%%在printf中可以输出显示为一个%号
-100可以控制进度条宽度为100位宽并且每次左对齐输出字符数组bar
process.c文件内容
2 #include "process.h"
3
4 char style[S_NUM]={'*','#','-','.','+'};
5 五种风格可以在makefile文件中修改N以控制风格样式
6 void ProncessOn()
7 {
8 int cnt=0;
9 //循环101次
10 char bar[NUM];
11 memset(bar,'\0',sizeof(bar));
12
13 const char*lable="|\\-/";
14
15 while(cnt<=100)
16 {
17 //printf("[%-100s][%-3d%%][%c]\r",bar,cnt,lable[cnt%4]);
18 printf("\033[42;34m[%-100s][%-3d%%][%c]\033[0m\r",bar,cnt,lable[cnt%4]);
19 fflush(stdout);
E> 20 bar[cnt++]=style[N];
21 usleep(60000);
22 }
23
24 printf("\n");
25 }