• Linux开发工具(4)——Makefile


    Makefile

    Makefile是Linux下的项目自动化构建工具。
    Makefile包含两部分,make是一个指令,makefile是一个文件。
    在makefile这个文件里面需要写两部分内容:

    1. 依赖关系
    2. 依赖方法

    makefile语法

    makefile的意义就是为了构建项目(完成某件事情),举个例子:依赖关系就是完成这件事情要依靠的各种人脉关系,依赖方法就是完成这件事情要做什么。

    makefile的语法,makefile写成Makefile也是没问题的。
    将makefile文件放入源代码所处的目录中。
    在这里插入图片描述

    这个就是makefile的语法,第一行是依赖关系,mytest是目标程序,test.c是依赖文件列表,可以是多个文件
    第二行必须以Tab开头,不可以用四个空格代替,第二行写的就是依赖方法,也就是完成任务所要做的动作。
    在这里插入图片描述

    有了makefile之后使用make指令就可以完成对源文件的编译。

    在这里插入图片描述

    新增一个clean功能,既然makefile可以自动化构建项目自然也可清理,这里的.PHONY修饰了clean表示clean是一个伪目标,伪目标就是可以保证目标一直被执行。clean没有依赖关系,也就是clean自己就可以完成任务不需要依赖任何人。

    makefile原理

    在这里插入图片描述

    make只有在第一次编译的时候才会进行更新,后序就不会进行更新因为没有对源文件进行修改自然不需要再重复编译,这是gcc的特性,因为在大型的项目中,编译一个项目少则几十分钟,多则几个小时,所以重复编译没有修改的代码就会造成时间的浪费。
    在这里插入图片描述

    clean是可以被重复执行的。因为clean被.PHONY修饰成伪目标所以其一直是被执行的。
    这里调用clean的使用的是make clean 因为在调用make的时候其实是省略了mytest,因为调用make的时候默认是从makefile的第一个依赖方法开始执行。所以在这里的make == make mytest。

    在这里插入图片描述

    如果将mytest也修饰成伪目标,那么他也可以每次都被执行。
    在这里插入图片描述

    但是不建议这样写,因为如果源文件代码没有被修改那么重复编译是没有意义的。

    gcc防止重复编译的原理就是通过比较可执行程序和源文件的Modify的时间,因为是先有了源文件再有了可执行程序所以,可执行程序的Modify时间一定比源文件早,如果源文件早,那么说明源文件在生成了可执行程序后又进行了修改,所以可以进行再次编译。
    在这里插入图片描述

    Access时间是访问时间,因为文件被访问的次数可能会很多,所以并不是一次访问文件,文件的Access时间就被更改,而是在一段时间内进行了多次的修改才会修改Access,可以减少在文件高频访问的时候每次都修改时间的性能消耗。
    Modify时间是文件内容被修改的时间
    Change时间是文件属性被修改的时间,一般伴随Modify时间的改变而改变,因为文件的大小也是属性,或者是修改文件的属性而改变。

    了解了为什么gcc可以禁止重复编译之后,.PHONY的原理也很明朗了,.PHONY修饰的目标可以编译是因为被.PHONY修饰了以后取消使用了gcc的时间比较策略。(每次make是不会影响test.c的时间的)

    makefile默认只会生成一个可执行程序。
    makefile的推导规则类似于栈,比如下面这样写makefile。
    在这里插入图片描述

    推导顺序是,mytest依赖于test.o但是现在没有test.o就去下面查看,发现test.o依赖于test.s然后test.s依赖于test.i继续推导test.i依赖于test.c最后test.c发现有这个文件,然后执行test.i的依赖方法生成了test.i然后向上回溯,用test.i生成了test.s 用test.s生成了test.o最后test.o生成了mytest。就是一个栈结构,先遇到的反而最后执行。
    在这里插入图片描述

    这张图的命令执行顺序也说明了,Makefile的推导顺序是栈结构的先进后出。

    Linux小程序

    倒计时小程序

    \n和\r的作用和区别,\r的作用时回车,\n的作用的换行,回车的意思就是将光标退回到这一行的开始,换行就是将光标移动到下一行,所以我们平时说的语言层面的回车是指\r + \n回车加换行。
    倒计时是指在一个位置显示从10到0的数字,并不是将这11个数字都打印出来,而是在一个位置显示,后面显示的数字会覆盖掉前面显示的数字。这时候就会用到\r让光标回到一行的最开始位置。使用一个sleep休眠函数,就可以了就像下面的代码

      1 #include<stdio.h>
      2 #include<unistd.h>
      3 
      4 int main()
      5 {
      6     int cnt = 10;
      7     while(cnt >= 0)
      8     {
      9         printf("%2d\r",cnt);
     11         sleep(1);
     12         cnt--;
     13     }
     15     return 0;
     16 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    但是运行这个代码什么都没有打印出来,这是因为printf打印出来的字符都是在行缓冲区里面,而行缓冲区是很大的,所以除非写满了行缓冲区会将所有的字符一起输出,或遇到了\n换行也会清空行缓冲区。还有一个函数fflush也可以用来清空行缓冲区。
    所以最终代码如下:

    1 #include<stdio.h>
      2 #include<unistd.h>
      3 
      4 int main()
      5 {
      6     int cnt = 10;
      7     while(cnt >= 0)
      8     {
      9         printf("%2d\r",cnt);
     10         fflush(stdout);
     11         sleep(1);
     12         cnt--;
     13     }
     15     return 0;
     16 }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    进度条程序

    进度条程序也是利用了\r回到行最开始的位置,和输出缓冲区的一个小程序代码。
    目标的样子是[##########################][100%][/],'#'代表进度条,后面的数字代表当前加载到的百分比。最后一个方框显示的是一条线在沿着顺时针转动,一般我们看到的进度条都有一个小标记来表示是不是卡死了。如果最后的线还在转说明程序没有卡死。

    //test.c
    //主函数所在的文件
    #include "process.h"
    int main()
    {
        Process();
        return 0;
    }
    //process.h
    //函数声明所在文件
    #include 
    #include 
    
    void func();//测试makefile的函数
    void Process();
    //process.c
    //函数实现所在的文件
    #include "process.h"
    
    void func()
    {
        printf("hello func\n");
    }
    
    void Process()
    {
        char arr[110] = {0};
        char brr[5] = {'|','/','-','\\'};
        int cnt = 0;
        while(cnt <= 100)
        {
            printf("[%-100s][%d%%][%c]\r",arr,cnt,brr[cnt%4]);
            fflush(stdout);
            usleep(100000);
            arr[cnt++] = '#';
        }
        puts("");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    最终的效果就是这样子。在这里插入图片描述

    当然如果想要更好看一些还可以更改颜色。C语言的printf是可以控制打印的颜色的
    主要格式就是:printf(“\033[字符背景颜色;字体颜色m要打印的字符串\033[0m]”);
    最后的0m是控制码
    字背景颜色范围: 40–49 字颜色: 30–39
    40: 黑 30: 黑
    41: 红 31: 红
    42: 绿 32: 绿
    43: 黄 33: 黄
    44: 蓝 34: 蓝
    45: 紫 35: 紫
    46: 深绿 36: 深绿
    47: 白色 37: 白色
    控制码:
    \033[0m 关闭所有属性
    \033[1m 设置高亮度
    \033[4m 下划线
    \033[5m 闪烁
    \033[7m 反显
    \033[8m 消隐
    \033[30m – \033[37m 设置前景色
    \033[40m – \033[47m 设置背景色
    \033[nA 光标上移n行
    \033[nB 光标下移n行
    \033[nC 光标右移n行
    \033[nD 光标左移n行
    \033[y;xH设置光标位置
    \033[2J 清屏
    \033[K 清除从光标到行尾的内容
    \033[s 保存光标位置
    \033[u 恢复光标位置
    \033[?25l 隐藏光标
    \033[?25h 显示光标

    printf("\033[47;35m[%-100s][%d%%][%c]\r\033[0m",arr,cnt,brr[cnt%4]); 
    
    • 1

    在这里插入图片描述

  • 相关阅读:
    clickonce 程序发布到ftp在使用cnd 加速https 支持下载,会不会报错
    Streamlit学习笔记
    一些JDK自带的性能分析利器
    Jenkins自动化部署
    elementUI 源码-打造自己的组件库,系列四:Dialog组件
    Maya v2024(3D动画制作软件)
    小米K8s运维-云原生方向(面经分享)
    一文讲清楚什么是类型化数组、ArrayBuffer、TypedArray、DataView等概念
    java计算机毕业设计ssm物流快递管理系统
    javaee springMVC的简单使用 jsp页面在webapp和web-inf目录下的区别
  • 原文地址:https://blog.csdn.net/qq_62745420/article/details/127913967