make和makefile

news/2024/7/21 15:02:32 标签: linux, vim, 开发语言

一、认识make和Makefile

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


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


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


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


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

二、初见make和Makefile

2.1、makefile的创建

这里我创建一个Makefile文件,直接使用 vim makefile,主义makefile的m可以大写也可以小写,我们在写makefile文件时,别打错字母,因为系统只认识makefile和Makefile;

注意: Makefile 文件中,命令行前面是用 tab 键来缩进的,不能用空格空格键
             如果命令行是用 tab 键来缩进,那命令行就会变颜色

 

makefile文件格式:

    目标文件:依赖文件
    			命令
  • 目标文件一般就是最终生成可执行文件,而生成目标文件需要去找他所需的所有依赖文件,如果依赖文件也需要其他的文件,就一直找,直到不需要依赖文件,就好比递归,需要一层一层递归,直到最后不需要为止
  • 这里拿 add.c add.h main.c 来举例,我现在需要把 add.c 和 main.c编译出可执行文件

2.2、make的使用

这里我们就把简单的Makefile文件创建好了,我们来在来创建我们要实现的add.c文件。

我们保存并退出,在命令行输入  make   编译我们的add.c

执行完该Makefile文件后,显示了文件中的执行命令,并且文件中多出了 add.o , main.o 还有我们想要的myadd可执行文件
我们写的这个Makefile中还有一句标签为

clean:
      rm -f *.o myadd

而这里的clean只是一个标签名,我们可以使用make工具来操作这行命令,例如

我们使用 make clean时就会

执行之后,所有 .o 文件和myadd可执行文件也被删除了

三、Makefile中的变量

3.1、自定义变量


Makefile 中允许使用等号自定义变量
Makefile中的变量定义和 shell 变量的定义非常相似,不同的是 Makefile中的变量的名称可以是任何不包含 :, #,= 和空字符的字符序列,并且等号两边可以有空格(shell 定义变量的等号两个不允许出现空格)
变量名=值 --等号两边不能有空格

3.2、变量的调用

在变量标识符前加美元符 $ 来引用,例如

如果你不想看到执行命令时,把makefile中的命令再打印一遍可以在makefile中的命令前加一个@

3.3、变量的赋值

Makefile一共提供了四个赋值运算符 (=、:=、?=、+=)

1).普通赋值 =

如果按照c语言的逻辑,var2应该等于12,但是这里最后打印var2的值为100,所以普通赋值表示赋值最新的变量值

2).立即赋值 :=

立即赋值则是直接赋值,不会在改变

3).询问赋值 ?=

如果该变量前面已经赋过值了,此次就不能再赋值了,如果没有就赋值,只有在该变量为空时才设置值

4.追加赋值 +=

类似字符串连接,将值追加到变量末尾,在追加的时候,自动添加空格

4.4、特殊变量

$^         --表示所有依赖文件
$@         --表示目标文件
$<         --表示第一个依赖文件
%          --通配符,表示所有,和linux中的 * 一样

利用这些特殊变量和自定义变量,我们就可以将Makefile文件写的更加简洁

 四、进度条的实现

我们使用make和makedile工具实现一个进度条的功能

4.1、预备知识

  • 换行和回车的区别
    • \r:回车,回到当前行的行首,而不会换到下一行,如果接着输出的话,本行以前的内容会被逐一覆盖,如果之前的内容比下一次来的的内容长,就不会被完全覆盖
    • \n:换行,换到当前位置的下一行,而不会回到行首
  1#include <stdio.h>
  2 int main()
  3 {
  4     printf("hello world\n");                                                                                                                               
  5     return 0;
  6 }

当然上面的实现是可以打印出 hello world

#include <stdio.h>
int main()
{
   printf("hello world\r");                                                                                                                               
   return 0;
}

第二个是打印不出来hello world

不难发现 \n 可以打印出来,而 \r,不能打印出来,因为显示器模式是行刷新缓冲区是按行缓冲的,没有\n,就不能立即刷新。 \r 回到行首后,会进行覆盖写,shell 提示符会覆盖掉之前写的 “hello world”,如果我们在 “hello world” 不加 \r,则不会进行覆盖写,shell 提示符会顺着 “hello world” 往后写。


缓冲区的理解

行缓冲是缓冲区刷新策略的一种,在行缓冲模式下,当输入和输出中遇到 ‘\n’ 换行时,就会刷新缓冲区,下面我们认识头文件<unistd.h>的三个函数

sleep : Linux 下的休眠函数,单位是秒
u s l e e p usleepusleep:和sleep 一样,单位ms(即10-6 m)
f f l u s h fflushfflush :刷新缓冲区

  1 #include <stdio.h>
  2 #include <unistd.h>                                                                                                                                       
  3 int main()
  4 {
  5     printf("hello world");
  6     sleep(3);
  7     return 0;
  8 }

我们知道函数代码语句是从上到下依次进行的,而我们看到的却是先休眠三秒,然后再打印出"hello world",原因是因为数据保存在缓冲区中,没有主动刷新。当程序退出后,保存在缓冲区中的数据被自动刷新出来了,如果我们想提前刷新,便可以调用f f l u s h fflushfflush函数来刷新缓冲区。

  1 #include <stdio.h>
  2 #include <unistd.h>                                                                                                                                       
  3 int main()
  4 {
  5     printf("hello world");
  6		fflush(stdout);
  7		printf("\n");
  8     sleep(3);
  9     return 0;
  10}


 

4.2进度条的实现

我们需要以下文件

main.c文件实现:宏定义,参数设置,函数调用和头函数包含

当然我们实现进度条都是要在一个场景下实现的,这里我模拟实现了一个下载的场景

  1 #include"processbar.h"
  2 #include<time.h>
  3 #include<stdio.h>
  4 #include<unistd.h>
  5 
  6 #define FILESIZE 1024*1024*1024
  7 //模拟一种场景,表示一种下载的任务
  8 void download(callback_t cb)
  9 {
 10     srand(time(NULL)^1023);
 11     int total=FILESIZE;
 12     while(total)
 13     {
 14         usleep(10000);    //下载动作
 15         int one = rand()%(1024*1024*10);
 16         total-=one;
 17         if(total<0)
 18         {                                                                                                                                          
 19             total=0;
 20         }
 21         int download=FILESIZE-total;
 22         double rate=(download*1.0/(FILESIZE))*100.0;  //0 23.4   45.6  67.5
 23         cb(rate);
 24     }
 25 }
 26 int main()
 27 {
 28   // process();
 29    download(process_flush);
 30     return 0;
 31 }
~
~

processbar.h文件实现

  1 #pragma once                                                                                                                                       
  2 #include<stdio.h>
  3 #include <stdlib.h>
  4 #define NUM 103
  5 #define Body '='
  6 #define Head '>'
  7 typedef void (*callback_t)(double);
  8 
  9 
 10 //version1
 11 void process();
 12 
 13 //version2
 14 void process_flush(double rate);
~

processbar.c文件实现

  1 #include"processbar.h"
  2 #include<string.h>
  3 #include<unistd.h>
  4 
  5 const char*lable="|/-\\";
  6 void process()
  7 {
  8     char buffer[NUM];
  9     memset(buffer,'\0',sizeof(buffer));
 10     int cnt=0;
 11     int n=strlen(lable);
 12     buffer[0]=Head;
 13     while(cnt<=100)
 14     {
 15         printf("[%-100s][%3d%%][%c]\r",buffer,cnt,lable[cnt%n]);
 16         fflush(stdout);
 17         buffer[cnt++]=Body;
 18         if(cnt<100)
 19         {
 20             buffer[cnt]=Head;
 21             usleep(500000);
 22         }
 23     }
 24     printf("\n");
 25 }
 26 
 27 //version2
 28 //进度是多少,进度条是不知道的。,另外,进度应该是依附于一个东西的,比如下载
 29 char buffer[NUM]={0};
 30 void process_flush(double rate)
 31 {
 32     static int cnt =0;
 33     int n=strlen(lable);                                                                                                                           
 34     if(rate<=1.0)
 35     {
 36         buffer[0]=Head;
 37     }
 38     printf("[\033[4;32;44m%-100s\033[0m][%.1f%%][%c]\r",buffer,rate,lable[cnt%n]);
 39     fflush(stdout);
 40 
 41     buffer[(int)rate]=Body;
 42     if((int)rate+1<100)
 43     {
 44         buffer[(int)(rate+1)]=Head;
 45     }
 46     if(rate>=100.0)
 47     {
 48         printf("\n");
 49     }
 50     cnt++;
 51     cnt%=n;
 52 }

makefile文件的实现

   processbar:main.o processbar.o                                                                                                                     
       gcc -o $@ $^
   main.o:main.c
       gcc -c main.c
   processbar.o:processbar.c
       gcc -c processbar.c
   
  .PHONY:clean
   clean:
      rm -f main.o processbar.o processbar

效果展示:

 


http://www.niftyadmin.cn/n/5184935.html

相关文章

骨传导蓝牙耳机推荐,这几款高性价比的耳机不容错过!

想必对于大多数人来说&#xff0c;蓝牙耳机在生活中的占比越来越重。而无线蓝牙耳机的应用也越来越广泛。从一开始对骨传导蓝牙耳机的质疑到接受&#xff0c;也确确实实走了一个很长的过程&#xff0c;科技的浪潮裹挟着年轻人的需求让各类数码产品层出不穷&#xff1a;靓丽的外…

systrace分析 之 问题初步定位

2、systrace分析 之 问题初步定位 1、找到问题点2、有buffer&#xff0c;SF却什么没有取 2.1、GPU 处理时间长导致2.2、区分HWC release 是否有异常&#xff1a;2.3、SF 异常导致2.4、SF 自身处理时间长2.5、RenderThread处理时间长3、案例分享 1、找到问题点 2、有buffer&a…

alpine 设置时区,dockfile里面配置

方法一 RUN apk update && apk add tzdata RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime RUN echo "Asia/Shanghai" > /etc/timezone方法二 RUN apk update && apk add tzdata RUN cp /usr/share/zoneinfo/Asia/Shanghai /…

DC电源模块对效率有什么要求?

BOSHIDA DC电源模块对效率有什么要求&#xff1f; DC电源模块是现代科技中非常重要的组成部分&#xff0c;它是将交流电转换为直流电的装置&#xff0c;可以提供稳定的电源给各种设备和系统使用。效率是DC电源模块的一个关键性能指标&#xff0c;直接影响着模块的整体性能和效…

【matlab学习】现代控制

文章目录 (1) SISO Modeling(2) MIMO Modeling(3) 状态空间模型(4) 状态空间模型->传递函数(5) 传递函数->状态空间模型(6) 状态空间模型变换(7) 特征值和特征向量(8) 广义特征向量(9) 状态空间模型->约旦型 (1) SISO Modeling y ( k 2 ) 5 y ( k 1 ) 6 y ( k ) …

三行Python代码即可将视频转Gif

一、前言 很多网站提供视频转GIF的功能&#xff0c;但要么收费要么有广告 实际上我们通过python&#xff0c;几行代码就能够实现视频转gif 二、教程 1. 安装必备库moviepy pip install moviepy -i https://pypi.tuna.tsinghua.edu.cn/simple 2. 写入代码 from moviepy.edi…

【ROS导航Navigation】五 | 导航相关的消息 | 地图 | 里程计 | 坐标变换 | 定位 | 目标点和路径规划 | 激光雷达 | 相机

致谢&#xff1a;ROS赵虚左老师 Introduction Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程 参考赵虚左老师的实战教程 一、地图 nav_msgs/MapMetaData 地图元数据&#xff0c;包括地图的宽度、高度、分辨率等。 nav_msgs/OccupancyGrid 地图栅格数据&#…

OpenAI暂停新的ChatGPT Plus注册 | OpenAI 的 GPT Builder 创建您的 GPTs

OpenAI DevDay 才过去仅仅一周时间&#xff0c;伴随着开发者大会上发布的一系列重磅升级和新特性&#xff0c;无疑这样的进化速度让广大网友炸锅了&#xff0c;其火热程度可见一斑。 就在四个小时前&#xff0c;OpenAI的CEO Sam Altma突然宣布&#xff0c;ChatGPT Plus账号暂停…