【Linux】项目自动化构建工具make / Makefile 及进度条小程序

简介: 【Linux】项目自动化构建工具make / Makefile 及进度条小程序

👉make项目管理器的基础👈


在实际应用中,一个 C 语言的工程项目常常由多个文件组成,此时为了对多个文件进行管理和处理,可以使用 make 项目管理器。


使用项目管理器的主要目的是用于管理较多的文件。在上一篇博客介绍过 C 语言代码的编译过程分为预处理、编译、汇编和链接,其中编译阶段仅检查语法错误以及函数与变量是否被正确地声明了,在链接阶段则主要完成函数链接和全局变量的链接。因此,那些没有改动的源代码根本不需要重新编译,只要把它们重新链接进去就可以了。这是, make 项目管理器就应运而生了。


实际上,make 项目管理器也就是个“自动编译管理器”。这里的“自动”是指它能够根据文件的时间戳自动发现更新过的文件而减少编译的工作量,同时其通过读入 makefile 文件的内容来执行大量的编译工作。用户只需编写一次简单的编译语句就可以了,所以大大提高了实际项目的工作效率。


注:make 是一个命令,而 makefile 是一个文件。


👉makefile的基本结构👈


makefile 是 make 项目管理器中使用的配置文件,其通常有一下几个部分组成。

目标体:make 项目管理器生成的目标文件或者可执行文件。

依赖文件:make 项目管理器创建目标体所需要的文件,通常是 C 语言的源文件和头文件等。

相关操作命令:make 项目管理器使用依赖文件来创建目标体所需要的命令,这些操作命令必须以制表符(Tab)开头。

makefile 存在的意义就是为了构建项目。

注:Makefile 也是可以的。


Makefile 文件样例


616edd32729e45a992f82119ff0691a6.png

0ef7660adc434cc1ae56ff2461e1a18b.png

make clean 清理文件

67baa4ad904d49cbbf4026bf5e03e248.png


7ada998ceb3a4142875af02aba0683b0.png


02d1cb4972a240f0804920d735bc7969.png


上图告诉我们,可执行程序 mycode 已经是最新了。为什么会这样呢?系统是如何得知的呢?为了解决这个问题,我们先来想一个问题:如果一份源代码没有任何的修改,该代码是否还需要再编译一次呢?答案是,肯定不需要。


虽然 make 指令连续使用,系统会提示你。但是 make clean 指令连续使用,系统并不会提示任何的信息。


1e9cc7fc9e9447ffb77ad87b06414448.png


其实这就是.PHONY的作用所在。被.PHONY关键字修饰的对象是伪目标,伪目标总是会被执行相关操作命令的。其实我们所要生成的目标体,也可以用.PHONY关键字修饰,那么 make 指令就可以被连续执行了。但是通常来说,我们所要生成的目标体是不需要被.PHONY关键字修饰的。

bcd771712bfe49fab0132b773d1918af.png4dd958c9f5024aa3b053784439041f7d.png


那么,我们现在来回答上面的问题:gcc 是如何得知我们的源代码不需要再编译了呢?这就需要涉及文件的三个时间了。

e243f1247774424caccee8df7baa6ab7.png

4c3d710db84949bb8b212464d95c9d5d.png

ac05fdadbe0f4d03b0099dfe0f9bdbf7.png


上图所示,我们多次访问 mycode.c 文件,但该文件的访问时间 Access 却没有变化,这是为什么呢?在之前,只要你访问了文件,那么文件访问时间 Access 就会改变。但是现在不会。因为在操作文件的时候,访问文件的操作比较多;如果每访问文件一次,就修改文件的访问时间 Access,那么 Access 时间将会被频繁地修改,这就需要进行更多次的 IO。而且文件的访问时间 Access 也不是特别的重要。所以新的 Linux 系统要求一段时间后访问文件,才会修改文件的访问时间。


知道了文件的三个时间,我们就能回到上面的问题了。第一次编译时,源代码的修改时间肯定是早于可执行程序的修改时间的。如果源代码的修改时间晚于可执行程序的修改时间,那么就需要重新编译源代码,否则不需要编译源代码。

d1cd4a2c96954dbea4078ab95649a2ff.png

touch 已经存在的文件 #将文件的时间更新为现在的时间


1f7f099df6fd4132827c9a2103f3c8f9.png


那么,.PHONY关键字就是不管源文件和可执行程序的修改时间的新旧,你只要帮我重新编译就行了。


注:makefile 中的第一个目标体,使用 make 命令时可以省略目标体名称。make 命令默认从上到下执行,执行形成一个目标体,形成一个目标体后,后面的相关操作命令便不会执行了。


cf842cdb328e429aa01fd0e7011d75f7.png

makefile 的依赖关系


6d71b6e9b4624755b30d578ee8e45ef9.png


:不建议这么来写 makefile 文件。


👉小程序进度条👈


缓冲区问题


sleep 函数原型


9b6cd007c79d4370adc279cbd2fddb01.png


1de309d88e5b423387aeed670f702b44.png

dd9038654c97486bad563548d6bb9bfe.png


现象:先打印字符串"you can see me...",然后睡了两秒。

e92792616cc849bd811932a516a805cb.png


d486e2e79fad4bbc9ddc0caeb5ee8001.png

现象:先睡两秒,再打印字符串"you can see me..."。


关于第二个列子的现象,首先执行的一定是 printf 函数,因为我们的代码是顺序结构。先执行 printf 函数不代表数据先显示。所以该现象的解释就是已经执行 printf 函数,只不过该数据没有被立即显示出来。睡完两秒后,数据才被刷新出来。那休眠的期间,printf 函数一定执行完成打印了,那么对应输出的数据在哪里呢?答案是在缓冲区里面!


那如果我们想要 print 函数打印的内容立即显示出来,怎么才能做到呢?答:调用 fflush 函数刷新缓冲区。


3f7bee8790874581a021f158f2e90ce0.png


11e1b58f6f19498c9a5912903c6a6dcd.png


cc976a08d3544ae9a3bd5977cf1abc0a.png


那想问大家一个问题:为什么第一个例子中加了个'\n'就能够马上打印内容呢?其实'\n'是行缓冲,有'\n'的话,就会把一行内容刷新出来,没有就不刷新。

现象:先打印字符串"you can see me...",然后睡了两秒。


回车和换行


  • 回车\r是回到当前行的最开始
  • 换行\n是换到下一行
  • 一般而言,\r\n是回车换行。但在语言层面上,\n就是回车换行


补充知识:显示器为什么能显示各种符号?显示器面板上有各种像素点,那么点亮显示器上对应的像素点就能显示各种符号了。凡是显示到显示器上的东西,都是字符。


倒计时程序


#include <stdio.h>
#include <unistd.h>
int main()
{
    int cnt = 10;
    while(cnt)
    {
        printf("剩余时间:%2d\r",cnt--); // %2d一次刷新两个字符
        fflush(stdout); // 刷新缓冲区
        sleep(1); // 休眠一秒钟
    }
    return 0;
}


进度条程序


dc76a777f5e54c32b6c891cff1399989.png


注:头文件不用在 makefile 里写,编译器能够在当前目录下找到。


// makefile文件里的内容,注:-D N=1为命令行参数
ProcessOn:process.c main.c
  gcc process.c main.c -o ProcessOn -D N=1
.PHONY:clean
clean:
  rm -f ProcessOn


// process.h
#pragma once
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define NUM 101
#define S_NUM 5
extern void  ProncessOn(); //函数的声明
// process.c
#include "process.h"
void ProncessOn() //函数定义
{
    int count = 0;
    char bar[NUM];
    memset(bar, '\0', sizeof(bar));
    //reserve
    const char* lable = "|/-\\";
    // 进度条样式
    char style[S_NUM] = {'+', '#', '>', '-', '.'};
    while(count <= 100)
    {
        printf("\033[42;34m[%-100s][%d%%][%c]\033[0m\r", bar, count, lable[count%4]);  //%-s向左对齐
        fflush(stdout);
        bar[count++] = style[N];
        //sleep(1); //sleep参数的单位为秒,休眠时间太长
        usleep(50000);    //usleep参数的单位为微妙
    }
    printf("\n");
}
// main.c
#include "process.h"
int main()
{
    ProncessOn(); //函数调用
    return 0;
}


颜色控制格式


1c054662eb6f4579a1d95f65f325ab1e.png

dc3bef81490a4a00be8dab70c8aa74c9.png



👉总结👈


本篇博客主要讲解 make、makefile 以及 Linux 下的第一个小程序进度条。那么以上就是本篇博客的全部内容了,如果大家觉得有收获的话,可以点个三连支持一下!谢谢大家!💖💝❣️


















相关文章
|
3月前
|
NoSQL Linux 开发工具
Linux环境基础开发工具的使用(yum、vim、gcc、g++、gdb、make/Makefile)
本文介绍了yum 包管理工具、Vim 编辑器、gcc/g++ 编译器、gdb 调试器、编译原理及 Makefile 的使用,同时还配备了如何使用,以及图解。旨在帮助读者更好地理解和应用这些工具与技术。
184 0
|
9月前
|
Linux Android开发 开发者
linux m、mm、mmm函数和make的区别
通过理解和合理使用这些命令,可以更高效地进行项目构建和管理,特别是在复杂的 Android 开发环境中。
431 18
|
11月前
|
Linux 开发工具
【Linux快速入门(二)】Linux与ROS学习之编译基础(make编译)
【Linux快速入门(二)】Linux与ROS学习之编译基础(make编译)
361 0
|
Java Linux C++
【Linux】Make和Makefile快速入门
【Linux】Make和Makefile快速入门
85 0
|
网络协议 Linux C语言
linux 系统获取网络ip, mask, gateway, dns信息小程序
net_util.c          #define WIRED_DEV                   "eth0"     #define WIRELESS_DEV                "ra0"               #define PPPOE_DEV                   "ppp0" #define DEBUG_PRT(fmt, arg.
1415 0
|
18天前
|
Unix Linux 程序员
Linux文本搜索工具grep命令使用指南
以上就是对Linux环境下强大工具 `grep` 的基础到进阶功能介绍。它不仅能够执行简单文字查询任务还能够处理复杂文字处理任务,并且支持强大而灵活地正则表达规范来增加查询精度与效率。无论您是程序员、数据分析师还是系统管理员,在日常工作中熟练运用该命令都将极大提升您处理和分析数据效率。
80 16
|
10天前
|
Linux
linux命令—stat
`stat` 是 Linux 系统中用于查看文件或文件系统详细状态信息的命令。相比 `ls -l`,它提供更全面的信息,包括文件大小、权限、所有者、时间戳(最后访问、修改、状态变更时间)、inode 号、设备信息等。其常用选项包括 `-f` 查看文件系统状态、`-t` 以简洁格式输出、`-L` 跟踪符号链接,以及 `-c` 或 `--format` 自定义输出格式。通过这些选项,用户可以灵活获取所需信息,适用于系统调试、权限检查、磁盘管理等场景。
|
2月前
|
监控 Linux 网络安全
Linux命令大全:从入门到精通
日常使用的linux命令整理
654 13
|
3月前
|
Linux 网络安全 数据安全/隐私保护
使用Linux系统的mount命令挂载远程服务器的文件夹。
如此一来,你就完成了一次从你的Linux发车站到远程服务器文件夹的有趣旅行。在这个技术之旅中,你既探索了新地方,也学到了如何桥接不同系统之间的距离。
525 21
|
3月前
|
JSON 自然语言处理 Linux
linux命令—tree
tree是一款强大的Linux命令行工具,用于以树状结构递归展示目录和文件,直观呈现层级关系。支持多种功能,如过滤、排序、权限显示及格式化输出等。安装方法因系统而异常用场景包括:基础用法(显示当前或指定目录结构)、核心参数应用(如层级控制-L、隐藏文件显示-a、完整路径输出-f)以及进阶操作(如磁盘空间分析--du、结合grep过滤内容、生成JSON格式列表-J等)。此外,还可生成网站目录结构图并导出为HTML文件。注意事项:使用Tab键补全路径避免错误;超大目录建议限制遍历层数;脚本中推荐禁用统计信息以优化性能。更多详情可查阅手册mantree。
linux命令—tree