make和makefile

news2025/1/22 21:36:12

一、认识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.coloradmin.cn/o/1214764.html

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

相关文章

借助Spire.Doc for Java控件,将 ODT 转换为 PDF。

在通过电子邮件发送或与其他人共享 ODT 文件之前&#xff0c;您可能需要将该文件转换为 PDF&#xff0c;以便任何人都可以跨多个操作系统访问该文件。在本文中&#xff0c;您将学习如何使用Spire.Doc for Java在 Java 中将 ODT 转换为 PDF。 Spire.Doc 是一款专门对 Word 文档…

中国生态功能保护区shp数据

代码 名称 类型 1 秦岭山地生态功能保护区 水涵养生态功能保护区 2 若尔盖一玛曲生态功能保护区 水涵养生态功能保护区 3 滇西北生态功能保护区 水涵养生态功能保护区 4 珠江源&#xff08;云南部分&#xff09;生态功能保护区 水涵养生态功能保护区 5 雅鲁藏布…

什么是游戏盾?怎么进行防护?

一.德迅游戏盾&#xff08;抗D盾&#xff09;概述 1.抗D盾是针对游戏行业推出的高度可定制的网络安全解决方案&#xff0c;可以针对大型DDoS攻击(T级别)进行有效防御&#xff0c;同时能彻底解决游戏行业特有的TCP协议的CC攻击问题。 2.抗D盾是新一代的智能分布式云接入系统&a…

骨传导蓝牙耳机排行榜,精选五款骨传导耳机推荐!

目前市面上的骨传导耳机大多是传统挂耳式&#xff0c;虽然佩戴更稳固&#xff0c;但是也限制住了其使用场景&#xff0c; 但近两年&#xff0c;有一款名为骨传导耳机的品类进入了大众的视野&#xff0c;它以独特的款式和超乎以往的佩戴舒适性迅速圈粉无数&#xff0c;并成为当下…

第一讲之递归与递推下篇

第一讲之递归与递推下篇 带分数费解的开关飞行员兄弟翻硬币 带分数 用暴力将所有全排列的情况都算出来 > 有三个数&#xff0c;a,b,c 每种排列情况&#xff0c;可以用两层for循环&#xff0c;暴力分为三个部分&#xff0c;每个部分一个数 当然注意这里&#xff0c;第一层fo…

【Spring进阶系列丨第二篇】Spring中的两大核心技术IoC(控制反转)与DI(依赖注入)

前言 我们都知道Spring 框架主要的优势是在 简化开发 和 框架整合 上&#xff0c;至于如何实现就是我们要学习Spring 框架的主要内容&#xff0c;今天我们就来一起学习Spring中的两大核心技术IoC&#xff08;控制反转&#xff09;与DI&#xff08;依赖注入&#xff09;。 文章目…

关于CISSP中文版计算机化自适应考试(CAT),你需要知道的!

进入ISC2宣布CISSP简体中文的线性考试(Linear Test)被取消&#xff0c;逐步实行CISSP中文版计算机化自适应考试&#xff08;CAT&#xff09;。接下来我根据ISC2官网和互联网中关于CAT相关信息&#xff0c;给大家对CISSP认证CAT进行介绍。 一、什么是CISSP认证线性考试&#xf…

实时云渲染技术在智慧园区中的广泛应用

智慧园区是指通过运用先进的信息技术&#xff0c;利用物联网、大数据、云计算等技术手段&#xff0c;来实现对园区内各类设备、设施和资源进行监测、管理、控制和优化的平台。这一概念旨在提高园区运行的效率、实现资源的可持续利用&#xff0c;并通过数字化和智能化手段来推动…

010.cat、find

1、用cat进行拼接 cat命令能够显示或拼接文件内容&#xff0c;不过它的能力远不止如此。比如说&#xff0c;cat能够将标准输入数据与文件数据组合在一起。通常的做法是将stdin重定向到一个文件&#xff0c;然后再合并两个文件。而cat命令一次就能搞定这些操作。 用cat读取文件…

QGIS之二十二矢量线交点处分割线

效果 步骤 1、准备数据 现有的线数据有部分线相交的地方并没有分割 2、分割 运行 3、结果

打造“下一个鹿晗”,是风华秋实的上市“通行证”?

今年以来&#xff0c;文娱公司们动作频频&#xff0c;乐华娱乐、巨星传奇接连“上岸”港交所。近日&#xff0c;因2010年一场“怒放”演唱会声名鹊起的风华秋实&#xff0c;也第七次向港交所递交了招股书。 据招股书披露&#xff0c;2020至2022年&#xff0c;风华秋实连续三年…

网站SEO优化

网站SEO优化 浏览722 一、合理的title、description、keywords 搜索对着三项的权重逐个减小&#xff0c;title值强调重点即可&#xff1b;description把页面内容高度概括&#xff0c;不可过分堆砌关键词&#xff1b;keywords列举出重要关键词。 1、title title&#xff0c;…

Java爬取哔哩哔哩视频(可视化)

链接&#xff1a;我的讲解视频https://www.bilibili.com/video/BV14e411Q7oG/ 本文仅供学术用途 先上图 代码 爬虫核心 import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.gargoylesoftware.htmlunit.*; import org.apache.commons.…

【500强 Kubernetes 课程】第3章 运行docker容器

一 - 三 &#xff0c;docker基础操作见 第2章7节 四、docker部署web网站 1、安装 nginx &#xff08;适合场景&#xff1a;学习 - 略&#xff09; 2、docker 安装 nginx Stage 1 &#xff1a;docker hub 上 搜索 nginx 镜像 Stage 2&#xff1a;拉取官方镜像 Stage 3&…

【开源】基于微信小程序、Vue和SpringBoot的智慧家政系统

项目编号&#xff1a; S 063 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S063&#xff0c;文末获取源码。} 项目编号&#xff1a;S063&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询家政服…

软件自动化测试代码覆盖率

在<professional software testing with visual studio 2005 team system tools for software developer>中提到了代码覆盖率&#xff0c;我很久没有去书店了&#xff0c;不知道是不是出了新的版本&#xff0c;觉得书里面关于代码覆盖率方面的知识有些地方没有讲&#xf…

wpf devexpress数据统计

GridControl允许显示总结信息关于单个数据行分组。例如&#xff0c;你可以显示记录数量&#xff0c;最小和最大值。这个统计信息可以叫做数据统计。 创建统计 GridControl 支持总结和分组统计&#xff1a; 总结统计 - 一个总结函数值计算对于所有列和视图显示统计面板和固定统…

04.智慧商城——短信验证码倒计时、登录请求、响应拦截器统一处理、请求loading效果

01. 短信验证倒计时功能 (1) 倒计时基础效果 准备 data 数据 data () {return {totalSecond: 60, // 总秒数second: 60, // 倒计时的秒数timer: null // 定时器 id} },给按钮注册点击事件 <button click"getCode">{{ second totalSecond ? 获取验证码 : s…

Go 使用Viper处理Go应用程序的配置

在开发Go应用程序时&#xff0c;处理配置是一个常见的需求。配置可能来自于配置文件、环境变量、命令行参数等等。Viper是一个强大的库&#xff0c;可以帮助我们处理这些配置。 什么是Viper&#xff1f; Viper是一个应用程序配置解决方案&#xff0c;用于Go应用程序。它支持JS…

Go fsnotify简介

fsnotify是一个用Go编写的文件系统通知库。它提供了一种观察文件系统变化的机制&#xff0c;例如文件的创建、修改、删除、重命名和权限修改。它使用特定平台的事件通知API&#xff0c;例如Linux上的inotify&#xff0c;macOS上的FSEvents&#xff0c;以及Windows上的ReadDirec…