【linux学习指南】Linux项目自动化构建工具 make /makefile进度条代码

news2024/9/21 0:49:49

请添加图片描述

文章目录

  • 📝前言
  • 🌠 Makefile 格式
    • 🌉Makefile命令符号
  • 🌠makefile/make基本原理
    • 🌉总和小案例
  • 🌠进度条代码
  • 🚩总结


📝前言

一个工程中的源文件多不技计数,其按其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作

makefile带来的好处就是一一“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大提高了软件开发的效率。

make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数IDE都说有这个指令,比如:Delphi的makevisual C++nmakeLinuxGNUmake。可见,makefile都成为了一种在工程方面的编译方法。

make是一条指令,makefile是一个文件,两个搭配使用,完成项目自动化构建。

🌠 Makefile 格式

Makefile 由一系列规则组成,每个规则的格式如下:

target: dependencies
    commands
  • target: 要生成的文件或目标。可以是文件名,也可以是一个标签(label)。
  • dependencies: 生成 target 所需的文件或目标,用空格分隔。
  • commands: 生成 target 所需执行的命令,每行一条命令,必须以制表符(\t)开头。

例如:
在这里插入图片描述

Makefile 语法

  1. 伪目标:
    .PHONY: clean
    clean:
        # commands
    
    伪目标不对应任何文件,通常用于定义常用的构建任务。

在这里插入图片描述

make 命令

常用的 make 命令有:

  • make: 构建 Makefile 中的默认目标。
  • make target: 构建指定的目标。
  • make clean: 清理构建产生的中间文件。
  • make all: 构建 Makefile 中的所有目标。
  • make -n: 显示执行命令,但不实际执行。
  • make -j <number>: 并行构建,指定同时执行的命令数量。

使用make命令,可以直接执行Makefile的文件命令
在这里插入图片描述
但是,当我再次执行make命令,这里的proc的文件无法再次执行:
在这里插入图片描述

这个问题是因为:

.PHONY是让目标文件,对应方法,总是被执行。(让依赖方法,忽略时间对比),这里的rm-f命令本来就不关心时间,只要make,这个指令就会执行,所以我们把.PHONY加在这里,无法看出效果。
在这里插入图片描述
把伪目标加在前面,让他忽略时间对比,仍然执行目标文件指令:gcc -o proc proc.c:如图:
在这里插入图片描述
make执行
在这里插入图片描述

这里提及到了时间,有一问题:对于源文件和可执行出程序,有时候需要重新编译有时候不需要?为什么?
对于源文件和可执行程序,可以说都是文件,而文件 = 内容 + 属性------》而属性其中包含了文件的时间:

stat命令:
stat 命令用于显示文件或文件系统的状态信息。它可以输出文件的各种属性,如文件类型、权限、所有者、大小、访问和修改时间等。

stat [OPTION]... FILE... 

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

🌉Makefile命令符号

Makefile 中,有几个常用的命令符号和特殊规则,它们用于定义和管理构建过程。以下是一些常用的命令符号和其用途:

  1. 命令符号 @
    • 用法@ 符号用于抑制命令的回显。通常,make 会在执行每一条命令时打印命令本身。使用 @ 符号可以让 make 只输出命令的结果,而不输出命令行。
    • 示例

#目标文件 依赖关系列表
2 .PHONY:proc
3 proc:proc.c
4 @echo “hello make”
5 @echo “hello make”
6 @echo “hello make”
7 @echo “hello make”
8
9 # gcc -o proc proc.c
10 #.PHONY:clean
11 clean:
12 rm -f proc

 ```

在这里插入图片描述

  1. 伪目标 .PHONY

    • 用法.PHONY 用于声明伪目标。伪目标不是实际存在的文件,而是用于执行特定的命令。声明伪目标可以防止与实际文件名冲突,确保每次 make 都执行相关命令。
    • 示例
      .PHONY: clean
      clean:
          rm -f *.o my_program
      
  2. 变量赋值

    • 用法Makefile 支持变量赋值,用于简化和重用配置。变量可以在 Makefile 中定义并在规则中使用。
    • 示例
      CC = gcc
      CFLAGS = -Wall -g
      TARGET = my_program
      
      $(TARGET): main.o utils.o
          $(CC) $(CFLAGS) -o $(TARGET) main.o utils.o
      
  3. 自动变量

  • 用法:自动变量在规则中使用,能够引用当前目标、依赖文件等。
  • 常见自动变量
    • $@:表示规则中的目标文件。
    • $<:表示第一个依赖文件。
    • $^:表示所有的依赖文件(去重)。
    • $?:表示比目标文件更新的所有依赖文件。
  • 示例
    program: main.o utils.o
        $(CC) -o $@ $^
    
    main.o: main.c
        $(CC) -c $<
    
    utils.o: utils.c
        $(CC) -c $<
    
  1. 条件判断
  • 用法:可以使用条件判断来决定是否执行某些规则或命令。
  • 示例
    ifeq ($(DEBUG), 1)
        CFLAGS += -g
    else
        CFLAGS += -O2
    endif
    
  1. 模式规则

    • 用法:模式规则允许你定义一类规则,从而简化多个类似文件的编译过程。
    • 示例
      %.o: %.c
          $(CC) -c $(CFLAGS) $< -o $@
      
  2. 内置规则

    • 用法make 提供了一些内置规则来处理常见的文件生成任务,例如编译 .c 文件到 .o 文件。如果不定义这些规则,make 会尝试使用默认规则。
    • 示例
      # 默认规则
      %.o: %.c
          $(CC) -c $(CFLAGS) $< -o $@
      
  3. 包括其他 Makefile

  • 用法:可以使用 include 指令来包含其他 Makefile 文件,以实现配置的模块化。
  • 示例
    include config.mk
    

这些符号和规则是编写和维护 Makefile 的基础,掌握它们可以帮助你更高效地管理构建过程。
在这里插入图片描述

🌠makefile/make基本原理

  • make解释makefile的时候,是会自动推导的。一直推导,推导过程,不执行依赖方法。直到推导到有依赖文件存在,然后在逆向的执行所有的依赖方法
Makefile  ⮀                                                                                                         ⮂⮂ buffers 
  1 #目标文件   依赖关系列表
  2 .PHONY:proc clean
  3 proc:proc.o
  4     gcc proc.o -o proc
  5 proc.o:proc.s
  6     gcc -c proc.s -o proc.o
  7 proc.s:proc.i
  8     gcc -S proc.i -o proc.s
  9 proc.i:proc.c
 10     gcc -E proc.c -o proc.i
 11 
 12 .PHONY:clean clean-all
 13 clean:
 14   rm -f proc.i proc.s proc.o proc
 15 clean-all:
 16   rm -f proc  

在这里插入图片描述

依赖关系
上面的文件 hello ,它依赖 hell.o
hello.o , 它依赖 hello.s
hello.s , 它依赖 hello.i
hello.i , 它依赖 hello.c
%makefile语法中的通配符
%.c:当前目录下所有的.c文件,展开到依赖列表中
依赖方法
gcc hello.* -option hello.* ,就是与之对应的依赖关系

原理
make是如何工作的,在默认的方式下,也就是我们只输入make命令。那么,

  1. make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
  2. 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“hello”这个文件,
    并把这个文件作为最终的目标文件。
  3. 如果hello文件不存在,或是hello所依赖的后面的hello.o文件的文件修改时间要比hello这个文件新(可
    以用 touch 测试),那么,他就会执行后面所定义的命令来生成hello这个文件。
  4. 如果hello所依赖的hello.o文件不存在,那么make会在当前文件中找目标为hello.o文件的依赖性,如果
    找到则再根据那一个规则生成hello.o文件。(这有点像一个堆栈的过程)
  5. 当然,你的C文件和H文件是存在的啦,于是make会生成 hello.o 文件,然后再用 hello.o 文件声明
    make的终极任务,也就是执行文件hello了。
  6. 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文
    件。
  7. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,
    而对于所定义的命令的错误,或是编译不成功,make根本不理。
  8. make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,
    我就不工作啦。

项目清理

  • 工程是需要被清理的
  • 像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。即命令——“make clean”,以此来清除所有的目标文件,以便重编译。
  • 但是一般我们这种clean的目标文件,我们将它设置为伪目标,用 .PHONY 修饰,伪目标的特性是,总是被执行的。
  • 可以将我们的 hello 目标文件声明成伪目标,测试一下。

依赖关系:右侧的依赖文件,一个一个一个的交给gcc -c选项,形成同名的.o文件

Makefile :                                                                                                      
  1 #目标文件   依赖关系列表
  2 
  3 proc:proc.o
  4     gcc proc.o -o proc
  5 %.o:%.c
  6   gcc -c $<                                                                                                                      
  7 
  8 .PHONY:clean
  9 clean:
 10   rm -f proc.o proc
 11   

在这里插入图片描述

在这里插入图片描述

Makefile+1 bin=proc
  2 src=proc.o
  3 $(bin):$(src)
  4     gcc %^ -o $@
  5 %.o:%.c
  6   gcc -c $<
  7                                                                                                                                  
  8 .PHONY:clean
  9 clean:
 10   rm -f proc.o proc
 11   

原型为:

proc1.c proc2.c proc3.c
%.o:proc1.c proc2.c proc3.c
gcc -c proc1.c -o proc1.o
以下同理:
gcc -c proc2.c
gcc -c proc3.c

在这里插入图片描述

🌉总和小案例

我们将使用gcc/g++, vim, make/makefile 进行制作一 linux第一个偏系统的一个样例程序︰进度条

  1. 回车与换行
    回车 (Carriage Return, CR): - 回车将光标移动到行首
  • 回车是一个控制字符:将光标移动到当前行的开头。
  • 在早期的打字机和电传打字机上,回车会使打字头或打字轮返回到行首。
  • 在 macOS 和早期的 Mac OS 系统中,文本文件使用回车 (ASCII 编码 0x0D) 作为行末标记。

换行 (Line Feed, LF): - 换行将光标移动到下一行

  • 换行是一个控制字符:将光标移动到下一行。
  • 在早期的打字机和电传打印机上,换行会使纸张向下移动一行。
  • 在 Unix/Linux 系统中,文本文件使用换行 (ASCII 编码 0x0A) 作为行末标记。

回车+换行 (CR+LF):

  • 在 Windows 系统中,文本文件使用回车+换行 (ASCII 编码 0x0D 0x0A) 作为行末标记。
  • 这是为了向后兼容早期的打字机和电传打印机,既移动光标到行首,又移动到下一行。
新起一行:本质:先回车,在换行
              \r      ln

在这里插入图片描述

  1. 缓冲区刷新:
    在 Linux 系统中,\r\n 在刷新缓冲区方面有以下区别:

\n (换行符):

  • 当遇到 \n 时,Linux 系统会将缓冲区中的数据立即刷新到输出设备(如终端或文件)。
  • 这是因为 \n 在 Linux 中被视为行末标记,表示一个完整的行已经写入。
  • 当缓冲区中有 \n 时,系统会立即将缓冲区中的数据刷新到输出设备,以确保数据能够及时显示。

\r (回车符):

  • 当遇到 \r 时,Linux 系统不会立即刷新缓冲区。
  • \r 只是将光标移动到当前行的开头,并不表示一个完整的行已经写入。
  • 缓冲区中的数据会一直保留在缓冲区中,直到遇到 \n 或者缓冲区被手动刷新。

手动刷新缓冲区:

  • 除了遇到 \n 时自动刷新,您也可以手动刷新缓冲区。
  • 常见的手动刷新方式包括调用 fflush() 函数或者关闭文件/终端。
  • 手动刷新可以确保缓冲区中的数据立即被写入输出设备,而不需要等待 \n 的出现。

总结:在 Linux 系统中,\n 会触发缓冲区的自动刷新,而 \r 不会。如果需要立即将缓冲区中的数据写入输出设备,可以手动调用 fflush() 或者关闭文件/终端。这样可以确保数据能够及时显示,而不需要等待 \n 的出现。

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

 #include <stdio.h>
 #include <unistd.h>
 int main()
 {
   printf("Hello world!");
   sleep(2);
 
   return 0;                                                                                                                    
 }  
  1. 首先会执行 printf("Hello world!"); 语句,将字符串 “Hello world!” 输出到标准输出(通常是终端)。

  2. 然后会执行 sleep(2); 语句,程序会暂停 2 秒钟。

在程序执行 sleep(2) 期间:

  • “Hello world!” 字符串已经被输出到标准输出了,此时它已经在终端上显示出来了。

  • 程序进入睡眠状态,不会执行任何其他操作,只是等待 2 秒钟后继续执行后续的语句。

所以,在程序执行 sleep(2) 期间,“Hello world!” 字符串已经被输出到终端上了,不会在缓冲区中等待。

这是因为 printf() 函数在 Linux 系统上默认是行缓冲的,也就是说当遇到换行符 \n 时,才会将缓冲区中的数据刷新到输出设备(终端)。在这个例子中,由于没有换行符,printf() 会立即将数据刷新到终端上。

所以,在程序执行 sleep(2) 期间,“Hello world!” 字符串已经显示在终端上了,不会在缓冲区中等待。

倒数:

Count.c
                                                                                            ⮂⮂ buffers 
 #include <stdio.h>
 #include <unistd.h>

 int main()
 {
     int count = 10;
    while(count >= 0)
     {
       printf("%d\r",count);//\r回车,但是没有换行也就咩有 刷新
         fflush(stdout);                                                                                                          
       count--;
       sleep(1);
     }
     printf("\r\n");
 }

显示器是一个一个刷新的,因此需要 printf(“%-2d\r”,count);整两个内存区域一起进缓冲区,一起刷新。
在这里插入图片描述
在这里插入图片描述

🌠进度条代码

版本1:
main.c:

#include "process.h"                                                                                                                                                                                   
int main()                                                                                         
{                                                                                         
   Process();                                                                                         
    return 0;                                                                                                                  
} 

process.h:请添加图片描述

#include <stdio.h>    
#include <string.h>    
#include <time.h>    
#include <unistd.h>    
    
//version 1    
void Process();  

process.c:

#include "process.h"

#define NUM 100
#define STYLE '='

//version1
void Process()
{
    const char * lable = "|/-\\";
    int len = strlen(lable);
    char bar[NUM + 1];
    memset(bar,'\0',sizeof(bar));
    int cnt = 0;
    while(cnt <= NUM)
    {
        printf("[%-100s][%d%%][%c]\r",bar,cnt,lable[cnt%len]);    
        fflush(stdout);       
        bar[cnt] = STYLE;                   
        cnt++;             
        if(cnt == NUM)    
        {                                                              
            bar[cnt-1] = STYLE;                                      
            printf("[%-100s][%d%%][%c]\r",bar,cnt,lable[cnt%len]);    
            break;                                                                                                                          
        }                                                    
        bar[cnt] = '>';                           
        usleep(50000);                                                                                       
    }                     
    printf("\r\n");

请添加图片描述


🚩总结

  1. makefile文件,会被make从上到下开始扫描,第一个目标名,是缺省要形成的。如果我们想执行其他组的依赖关系和依赖方法,make name
  2. make makfile在执行gcc命令的时候,如果发生了语法错误,就会终止推导过程
  3. make解释makefile的时候,是会自动推导的。一直推导,推导过程,不执行依赖方法。直到推导到有依赖文件存在,然后在逆向的执行所有的依赖方法
  4. make默认只形成一个可执行程序

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2115888.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

某部门系统主机中病毒分析

一、安全巡检 正在写着代码&#xff0c;我的电脑火绒软件提示有内网攻击&#xff0c;关于一个古老的漏洞&#xff1a;“永恒之蓝”。瞬间来了兴趣&#xff0c;不会现在仍然有电脑中这病毒吧&#xff0c;打开绿盟安全管理平台。根据IP查询记录&#xff0c;果然有很多漏洞。 发…

《深入浅出WPF》读书笔记.11Template机制(上)

《深入浅出WPF》读书笔记.11Template机制(上) 背景 模板机制用于实现控件数据算法的内容与外观的解耦。 《深入浅出WPF》读书笔记.11Template机制(上) 模板机制 模板分类 数据外衣DataTemplate 常用场景 事件驱动和数据驱动的区别 示例代码 使用DataTemplate实现数据样式…

2024Mysql And Redis基础与进阶操作系列(1)作者——LJS[含MySQL的下载、安装、配置详解步骤及报错对应解决方法]

目录 1.数据库与数据库管理系统 1.1 数据库的相关概念 1.2 数据库与数据库管理系统的关系 1.3 常见的数据库简介 Oracle 1. 核心功能 2. 架构和组件 3. 数据存储和管理 4. 高可用性和性能优化 5. 安全性 6. 版本和产品 7. 工具和接口 SQL Server 1. 核心功能 2. 架构和组…

唯徳知识产权产权系统存在任意文件读取漏洞

漏洞描述 深圳市唯德科创信息有限公司&#xff08;以下简称&#xff1a;唯德&#xff09;于2014年在深圳成立&#xff0c;是专业提供企业、代理机构知识产权管理软件供应商&#xff0c;唯德凭借领先的技术实力和深厚的专利行业积累&#xff0c;产品自上市推广以来&#xff0c;…

一文讲懂Spring Event事件通知机制

目录 一 什么是spring event 二 怎么实现spring event 一 什么是spring event 我不会按照官方的解释来说什么是spring event&#xff0c;我只是按照自己的理解来解释&#xff0c;可能原理上会和官方有偏差&#xff0c;但是它的作用和功能就是这个&#xff0c;我更加偏向于从他…

CTK框架(三): 插件的安装

目录 1.方式1&#xff1a;使用ctk框架工厂&#xff0c;适用于调用普通的插件 1.1.步骤 1.2.实现 2.方法2&#xff1a;使用ctk框架启动器&#xff0c;适用于需要eventadmin时 2.1.实现 3.注意事项 1.方式1&#xff1a;使用ctk框架工厂&#xff0c;适用于调用普通的插件 1…

Linux服务器应急响应(下)

目录 介绍步骤 介绍 Linux alias命令用于设置指令的别名。 用户可利用alias&#xff0c;自定指令的别名。若仅输入alias&#xff0c;则可列出目前所有的别名设置。alias的效力仅及于该次登入的操作。若要每次登入是即自动设好别名&#xff0c;可在.profile或.cshrc中设定指令…

ggplot2 缩小的、带箭头的坐标轴 | R语言

1. 效果图 左侧为DimPlot2()效果图。 右侧为DimPlot()效果图&#xff0c;原图。 2. 代码 # DimPlot with 缩小的坐标轴 # # param scObject # param reduction # param group.by # param label # param raster # param legend.position # param ... # # return # expo…

OCC开发_变高箱梁全桥建模

概述 上一篇文章《OCC开发_箱梁梁体建模》中详细介绍了箱梁梁体建模的过程。但是&#xff0c;对于实际桥梁&#xff0c;截面可能存在高度、腹板厚度、顶底板厚度变化&#xff0c;全桥的结构中心线存在平曲线和竖曲线。针对实际情况&#xff0c;通过一个截面拉伸来实现全桥建模显…

长短期记忆神经网络-LSTM回归预测-MATLAB代码实现

一、LSTM简介&#xff08;代码获取&#xff1a;底部公众号&#xff09; 长短期记忆神经网络&#xff08;Long Short-Term Memory, LSTM&#xff09;是一种循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;的变体。相比于传统的RNN&#xff0c;LSTM能够更好…

nvidia-smi 随机掉卡,error,禁用GSP功能

问题 NVIDIA 驱动中默认开启加载GPU卡的GSP功能&#xff0c;会随机导致在执行nvidia-smi命令的时候读取GPU卡为ERR状态&#xff0c;或者导致smi命令卡死&#xff1b; 如下图&#xff0c;以A800为例&#xff0c;Centos系统&#xff1b; 涉及到的包含以下型号的GPU卡&#xff…

C#中chart绘制曲线

官网资料&#xff1a;Chart 类 (System.Windows.Forms.DataVisualization.Charting) | Microsoft Learn 类的 Chart 两个重要属性是 Series 和 ChartAreas 属性&#xff0c;这两个属性都是集合属性。 Series集合属性存储Series对象&#xff0c;这些对象用于存储要显示的数据以…

2024年全新deepfacelive简易版-傻瓜式使用教程-采用AI换脸软件deepfacelive

# 2024年全新deepfacelive简易版-傻瓜式使用教程-采用AI换脸软件deepfacelive # 下载安装deepfacelive 官网下载&#xff1a; https://github.com/iperov/DeepFaceLive/ 下载好后放在至少有 30G以上的盘&#xff0c; # 启动使用-设置中文 解压好后&#xff0c;双击.bat批处理…

GPT系列之:GPT-1,GPT-2,GPT-3详细解读

一、GPT1 论文&#xff1a;Improving Language Understanding by Generative Pre-Training 链接&#xff1a;https://cdn.openai.com/research-covers/languageunsupervised/language_understanding_paper.pdf 启发点&#xff1a;生成loss和微调loss同时作用&#xff0c;让下…

java常用集合方法

目录 一、Iterator接口二、Iterable接口三、Collection接口四、Collection与Iterable关系 一、Iterator接口 Iterator 是一个集合迭代器接口&#xff0c;它提供了以下方法&#xff1a; 判断迭代器中是否还拥有元素&#xff0c;有则返回true&#xff0c;否则返回false boolean …

实验八 输入/输出流

实验目的及要求 目的&#xff1a;通过实验掌握java提供的输入/输出包中类的使用&#xff0c;特别是一些常用的类的方法的使用&#xff0c;运用流的概念实现对象的序列化。 要求&#xff1a; &#xff08;1&#xff09;编写程序使用BufferedReader和BufferedWriter对文件进行…

Java高级编程—网络编程(完整详解,包括UDP通信方式、TCP通信方式、TCP三次握手、TCP四次挥手,附有代码+案列)

文章目录 二十九.网络编程29.1 概述29.2 InetAddress29.3 UDP通信29.3.1 UDP通信发送数据29.3.2 UDP通信接收数据29.3.3 Test 29.4 UDP的三种通信方式29.4.1 单播29.4.2 组播29.4.3 广播 29.5 TCP通信29.6 TCP通信三次握手29.7 TCP通信四次挥手29.8 Test29.8.1 多次发送 二十九…

Java数据结构(九)——选择排序、堆排序

文章目录 选择排序算法介绍代码实现复杂度和稳定性 堆排序算法介绍代码实现复杂度和稳定性 选择排序 算法介绍 选择排序是一种简单直观的排序算法。它的工作原理是&#xff1a;首先在未排序序列中找到最小&#xff08;大&#xff09;元素&#xff0c;存放到排序序列的起始位置…

【二分查找】锦集

二分查找锦集 二分前言1. 二分查找1.1 题目来源1.2 题目描述1.3 代码展示 2. 在排序数组中查找元素的第一个和最后一个位置2.1 题目来源2.2 题目描述2.3 解题分析 3. 搜索插入位置3.1 题目来源3.2 题目描述3.3 解题分析 4. x 的平方根4.1 题目来源4.2 题目描述4.3 解题分析 5. …

Oracle rman 没有0级时1级备份和0级大小一样,可以用来做恢复 resetlogs后也可以

文档说了 full backup 不能 用于后续的level 1&#xff0c;没说level 1没有level 0 是不是level 1就是level 0&#xff1f; 1级备份变0级的原因 及 Enabling Change Tracking生效没有-CSDN博客 这个文档说明1级备份时没有找到0级就是0级备份&#xff0c;可以用来完整恢复的。…