当前位置: 首页 > article >正文

我与Linux的爱恋:自动化构建工具-make/Makefile


外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

🔥个人主页guoguoqiang. 🔥专栏Linux的学习

Alt

文章目录

  • 背景
  • makefile的使用
  • .PHONY
    • makefile中常用选项
    • makefile的自动推导
  • 进度条程序
    • 倒计时程序
  • 实现进度条

背景

-会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力

  • 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的
    规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂
    的功能操作
  • makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编
    译,极大的提高了软件开发的效率。
  • make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命
    令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一
    种在工程方面的编译方法。
  • make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。

makefile的使用

makefile主要由两部分组成 1.依赖关系 2.依赖方法
首先我们要创建打开makefile文件

vim makefile

打开后开始写入内容
在这里插入图片描述
再查看一下text.c中的内容
在这里插入图片描述
在这里插入图片描述
查看当前目录后执行make,如何发现mytest文件,然后执行。
在这里插入图片描述

.PHONY

当我们要删除文件时应该怎么操作呢?
我们这时需要使用.PHONY来修饰。
PHONY是一个特殊的目标标记,用于告诉make工具,该目标不是一个真正的文件名,而是一个伪目标。
因为我们使用clean的目的是清除某些文件,而删除操作又不需要依赖文件,所以我们创建了一个伪目标,然后依赖这个伪目标,然后执行依赖方法。
在这里插入图片描述
在这里插入图片描述
我们执行make clean就发现mytest被删除了。
如果我们不修改text.c然后一直执行make会发生什么呢?
在这里插入图片描述
在这里插入图片描述
然后就发现可以一直make clean但是不能一直make
原因就是.PHONY的作用
在makefile中如果我们想无限执行mytest,只需将.PHONY:目标文件 即可

在这里插入图片描述

在这里插入图片描述
无限执行mytest并不好,未修改源文件而持续执行make会给编译器造成负担,但是可以无限执行clean,因为清理是必要的。
刚刚我们在重复make时看到提示说 mytest文件已经最新了。
那么编译器如何判断我的可执行程序为最新的呢?----->是根据文件的最新修改时间。
stat可以查看一个文件重要的三个时间​
在这里插入图片描述
Access:最近的访问时间.

Modify: 最近的内容修改时间,比如你修改了文件的内容,这个时间就会改变.

Change:最近的属性修改时间,比如你修改了这个文件的读写权限,这样它的属性修改时间就会被修改.

一个文件是由内容+操作属性组成(一个空文件在系统中也占内存),如果文件的内容被修改,那么文件的大小也会被修改,相关的属性也会发生变化,并且可执行文件形成的时间一定比源文件晚,比较一下时间,只要可执行文件的时间比源文件晚,就说明这个可执行文件一定是最新的。
执行make默认执行的是第一个依赖关系和依赖方法。

makefile中常用选项

写一下makefile中的内容
在这里插入图片描述
在这里插入图片描述
说明:

1 makefile支持定义变量,这是一门解释性语言,无需像C语言那样 int a = 10;

2 可以理解为取出对象; 可以理解为取出对象; 可以理解为取出对象;@ 是一个特殊变量,它代表当前规则的目标文件名;$^ 是一个特殊的宏,它代表当前规则的所有前置条件(即依赖文件列表)

3 通过观察可知,echo是用来打印内容的,但是在这个echo中,$(src) $(bin)会被替换打印

4 如果我们执行make/clean语句,不想打印出相关信息,可以在依赖方法前加@表明@:在命令前使用@可以阻止make打印这条命令

在Makefile中, @ 表示生成的目标文件, @表示生成的目标文件, @表示生成的目标文件,<表示从依赖文件列表中取出一个文件,对应的还有$^表示依赖文件列表中的所有文件

而对于gcc来说,在Makefile中可以使用内置变量CC(表示C编译器的名字)代替

在这里插入图片描述
在这里插入图片描述

makefile的自动推导

在这里插入图片描述
在这里插入图片描述
发现make/makefile会自动根据文件中的依赖关系,进行自动推导,帮助我们执行所有相关的依赖方法。
注意:

  1. 语句第一条必须是最终结果,如果最终目标颠倒顺序,程序不可执行

  2. 除了最终结果代码之外,其余的可以随意调换位置

  3. 整个推导过程是递归的,与栈类似

在这里插入图片描述

进度条程序

我们先了解一下\n 与 \r
在c语言和其他高级语言中 \n表示回到下一行开始,但是在实际上这是\r +\n
回车(\r):回到当前光标所在行的开始
换行(\n):前往光标所在行的下一行,但是光标是平行向下移动
在这里插入图片描述
输出缓冲区:
观察下面程序运行的结果:

#include <stdio.h>
#include <unistd.h>
 
int main()
{
    printf("hello linux\n");
    sleep(2);
    return 0;
}

如果在Linux终端运行该程序,可以看到程序先打印了hello linux,然后等待了2秒才显示prompt提示

#include <stdio.h>
#include <unistd.h>
 
int main()
{
    printf("hello linux");
    sleep(2);
    return 0;
}

可以看出程序先等待了两秒,如何再打印的hello linux 。
c语言默认是从上往下顺序执行代码,之所以会发生这样是因为缓冲区的存在,程序在输出时并不会直接将内容输出到显示器中,而是先输出到缓冲区中,再通过刷新结束缓冲区将内容打印到屏幕上,而之所以在有\n时会显示再等待是因为\n刷新了缓冲区,导致内容打印到了屏幕上。

如果使用将\n替换为\r则同样会先等待再打印,因为\r也不具备刷新缓冲区的效果,如果在当前情况下想刷新缓冲区但又不想使用\n,则可以使用fflush()函数,传递参数为标准输出stdout

#include <stdio.h>
#include <unistd.h>
 
int main()
{
    printf("hello linux");
    fflush(stdout);
    sleep(2);
    return 0;
}

倒计时程序

#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;
}

实现进度条

思路:首先要创建三个文件,分别是测试文件 main.c 和头文件process.c和实现文件process.c。对于进度条实际上就是打印原数组内容,再填充数组然后刷新缓冲区,对于百分比就是一个循环来控制,对于最右侧的变化符号,就是指定范围内进行循环。

	// 实现文件
#include "process.h"

void process()
{
    char bar[NUM] = {0};// 进度条数组
    int count = 0;
    const char *label = "|/-\\";//控制进度条最右侧的闪烁符号(| 顺时针旋转)
    size_t len = strlen(label);
    while(count <= 100) 
    {
        // [%-100s]预留100个字符的位置,每一次打印数组bar中的字符,因为初始化为0,所以数组中全是'\0',当遇到第一个'\0'就停止,加上-表示从右往左(默认从左往右)打印
        // 使用count控制进度条百分比,百分号%需要额外转义
        // label闪烁符号,使用count%4使下标循环在0-3,思路可以联想循环队列数组版控制下标轮回的方式
        printf("[%-100s][%d%%][%c]\r", bar, count, label[count%len]);
        fflush(stdout); // 先刷新缓冲区,打印出停留在缓冲区的内容
        bar[count++] = STYLE; // 向数组中添加字符
        usleep(20000);// 睡眠时间单位为微秒,1秒 = 1000毫秒=1000000微秒
    }
    printf("\n");
}
void procBar(double total,double current){
      char bar[NUM]={0};
      int len=strlen(label);
      int cnt=0;
      double rate=(current*100.0)/total;
      int loop_count=(int)rate;
      while(cnt<=loop_count){
        bar[cnt++]=STYLE;
      }
      printf("[%-100s][%.lf%%][%c]\r",bar,rate,label[cnt%len]);                                                                                                                          
      fflush(stdout);
    }


// 头文件
#include <stdio.h>
#include <unistd.h>
#include <string.h>

#define NUM 101 // 定义进度条字符的个数
#define STYLE '#' // 定义进度条的样式

void process();

// 测试文件
#include "process.h"

int main()
{
    process();
    return 0;
}

对应的makefile

	TARGET=process
SRC=process.c main.c

$(TARGET):$(SRC)
    gcc $^ -o $@

.PHONY:clean
clean:
    rm -rf $(TARGET)
    ```

http://www.kler.cn/news/303846.html

相关文章:

  • 测试-Gatling 与性能测试
  • 98、RS485全自动收发电路入坑笔记
  • Gmtracker_深度学习驱动的图匹配多目标跟踪项目启动与算法流程
  • ES机制原理
  • linux ubuntu编译 openjdk11
  • 中国科技统计年鉴1991-2020年
  • JDBC客户端连接Starrocks 2.5
  • python-回文数(一)
  • 4G MQTT网关在物联网应用中的优势-天拓四方
  • 组播 2024 9 11
  • 为什么mac打不开rar文件 苹果电脑打不开rar压缩文件怎么办
  • 基于Java-SpringBoot+vue实现的前后端分离信息管理系统设计和实现
  • element实现动态路由+面包屑
  • Vue的学习(三)
  • vue2响应式系统是如何实现的(手写)
  • 代码随想录刷题day32丨动态规划理论基础,509. 斐波那契数, 70. 爬楼梯, 746. 使用最小花费爬楼梯
  • 基于Python实现一个庆祝国庆节的小程序
  • Kubernetes 与 springboot集成
  • 【九盾安防】叉车使用安全新升级!指纹识别锁,验证司机操作权限
  • 关于我的阿里云服务器被入侵 - 分析报告
  • 春日课堂:SpringBoot在线教育解决方案
  • 限流,流量整形算法
  • 安全基础设施如何形成统一生态标准?OASA 硬件安全合作计划启动 | 2024 龙蜥大会
  • 【贪心算法】(二)贪心算法区间问题及进阶习题
  • 重学SpringBoot3-集成RocketMQ(二)
  • Python(TensorFlow和PyTorch)及C++注意力网络导图
  • Docker 安装 Nacos 教程
  • L3级智能网联汽车准入试点详细解析及所需材料
  • oracle 如何查死锁
  • Web大学生网页作业成品——动漫喜羊羊网页设计与实现(HTML+CSS)(4个页面)