Linux第八节 - make / mikefile

news2024/11/16 7:55:14

一、补充与复习

Linux在运行可执行程序的时候,有两种运行方式:

./mytest

(表示当前路径下的可执行程序 - 用/分隔开)

/home/shy/108/lesson8/mytest

(也可以运行程序,但是是在绝对路径下!)

在Linux系统中执行任意一个程序,必须在系统中找到这个程序对应的二进制文件。

(指令不需要加路径就能找到是因为系统的默认设置! --- 环境变量)

二、make / makefile

1、创建的makefile文件首字母不区分大小写!

2、依赖方法不是4个空格!是tab键!

3、makefile使用#注释

实例1:尝试写一个makefile文件

第一行为依赖关系;

第二行为依赖方法;

  1 mytest:mytest.c
  2   gcc -o mytest mytest.c
  3 clean:
  4   rm -f mytest       

通过make来编译;通过make clean清除可执行程序;

如果我们详细的写出每一步:

  1 mytest:mytest.o
  2   gcc -o mytest mytest.o
  3 mytest.s:mytest.i
  4   gcc -S mytest.i -o mytest.s
  5 mytest.o:mytest.s
  6   gcc -c mytest.s -o mytest.o
  7 mytest.i:mytest.c
  8   gcc -E mytest.c -o mytest.i                                                                                            
  9 clean:
 10   rm -f mytest

make会自动推导makefile中的依赖关系---栈式结构(不区分顺序)

  • make会在makefile中自动搜索第一个目标文件作为默认的目标文件(如果clean放在最首端,则此时执行make会默认执行clean!------ 因此建议将clean放到最后面!)
  • 还可以单独执行生成一个目标文件:例如make mytest.i

可以发现,当我们执行完make之后,如果源文件没有修改,再次执行make不会重新编译!

目的:为了提高编译效率!

怎么做到的?

一定是源文件形成可执行,才有源文件;一般来说,源文件的最近修改时间比可执行老;

如果修改了源文件,历史上曾经还有可执行,那么源文件的最近修改时间,一定要比可执行程序新!

因此!只需要比较可执行程序的最近修改时间和源文件的最近修改时间即可!

  • .exe新于.c源文件,说明不需要重新编译;
  • .exe老于.c源文件,需要重新编译;
  • 一般来说.exe 的修改时间不等于.c的修改时间

通过指令stat可以查看文件相关的时间属性:

stat mycode.c

文件分为:文件内容 + 文件属性 

  • Access:  文件被访问的时间(cat / vim / 增删改查等)
  • Modify: 文件被修改(文件内容被修改)的时间 ()
  • Change:  文件被改变(文件属性被修改)的时间 ()

一般情况下:文件内容被修改,文件的属性也会被修改!(例如增删查改内容,导致文件的大小被修改 > 文件的属性被修改 > 且在修改文件的时候打开了文件,AMC都被修改!

但是如果只是chmod + 文件的权限  --- 没有修改内容 --- 导致只有change修改!

可以发现:有时候Modify和Change的时间发生改变,但是Access的时候不变,这是由于access一直修改的话太过于频繁,不利于整机效率的提高。

如果我们想更新整个文件的时间,可以使用下面命令:

touch mytest.c

如果一个文件没有被创建,touch则是创建一个新文件,如果该文件已经被创建,则是更新该文件的时间!

touch -a mytest.c

只更新access时间!

一般来说,比较两个文件的新旧时间,通常比较的是Modify!

make会根据源文件和目标文件的新旧,判定是否需要重新执行依赖关系进行编译!

此时只要我们重新更新一下源代码的时间,即可重新编译!

如果我们想要对应的依赖关系总是被执行?!(引入伪目标关键字.PHONY)

例如:

  1 .PHONY:mytest                                                                                     
  2 mytest:mytest.o
  3   gcc -o mytest mytest.o
  4 mytest.s:mytest.i
  5   gcc -S mytest.i -o mytest.s
  6 mytest.o:mytest.s
  7   gcc -c mytest.s -o mytest.o
  8 mytest.i:mytest.c
  9   gcc -E mytest.c -o mytest.i
 10 clean:
 11   rm -f mytest mytest.i mytest.s mytest.o

加入.PHONY:mytest之后,生成的mytest不受时间约束!,可以一直执行make!

一般建议:清理指令用.PHONY修饰!

  1 mytest:mytest.c
  2   gcc -o mytest mytest.c
  3 .PHONY:clean
  4 clean:
  5   rm -f mytest                                                                                   

引入两个自动变量:

makefile 中,$@ 和 $^ 是特殊的自动变量,用于代表特定的目标和依赖关系。 

$@表示依赖关系左边,即需要生成的目标文件;

$^表示依赖关系右边,即需要的源文件!

如下:

  1 mytest:mytest.c
  2   gcc -o $@  $^
  3 .PHONY:clean
  4 clean:
  5   rm -f mytest                                                                                    

可以发现:当我们执行make / make clean的时候,对应的指令会回显出来!

如果我们不想回显,可以在对应的依赖方法加入@符号!

  1 mytest:mytest.c
  2   @gcc -o $@  $^
  3 .PHONY:clean
  4 clean:
  5   @rm -f mytest                                                                                    

三、进度条小游戏 

1、回车换行

在C语言中,一个\n执行的是回车 + 换行!

但是回车不等于换行!

回车:把光标移动到当前行的最左端!

换行:从该行当前位置直接移动到下一行!

如果我们只想进行回车:\r

2、缓冲区

使用makefile编写进度条小程序:

  • makefile中目前不用体现出头文件,编译只需要带.c文件即可(只要对应的.c文件中包含了头文件即可)
  • 如果需要调用sleep函数:在Linux系统中需要调用#include<unistd.h>;在windows系统中需要调用#include<windows.h>

接下来我们对代码进行调试:(修改main.c的代码)

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

 运行./processBar可以发现打印hello world后休眠了2秒!

如果我们此时再将\n去掉:

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

看到的结果变成了先休眠两秒,再打印hello world!

C语言的规则一定是先执行printf再进行sleep睡眠!(在sleep期间,"hello world"一定是被保存起来的!--- 被保存到了缓冲区!>>>  就是由C语言维护的一段内存!>>> stdout)

默认的是程序结束 / 程序退出内容才会被刷新出来!

怎么进行强制刷新?

C语言默认会打开三个流:标准输入(FILE* stdin)、标准输出(显示器,FILE* stdout)、标准错误(FILE* stderr)

fflush函数用于刷新一个流:

int fflush(FILE* stream);

因此,如果此时我们想要快速的进行刷新:fflush(stdout);

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

接下来可以尝试写一个倒计时(覆盖当前位置的时间) :

此时我们可以借鉴 \r + 刷新流:

  1 #include"processBar.h"
  2 #include<unistd.h>
  3 int main()
  4 {
  5   int cnt = 9;
  6   while(cnt>=0)
  7   {
  8   printf("%d\r",cnt);
  9   fflush(stdout);
 10   cnt--;
 11   sleep(1);
 12   }
 13   printf("\n");       // 回车的作用为使得倒计时的命令行不被覆盖掉                                                                            
 14  // printf("hello world"); // 1
 15  // fflush(stdout);
 16  // sleep(2);   //2
 17   return 0;
 18 }

但是!如果此时我们想倒计时从10~0,将cnt改为10,会发现打印的是10 - 90 - 80.....

这是因为显示器显示的是字符!数字123实际上是字符1,字符2,字符3......

 解决方法:直接显示两个位宽的字符!这样子覆盖会使得第一个位置为空!(默认为右对齐!)

  1 #include"processBar.h"
  2 #include<unistd.h>
  3 int main()
  4 {
  5   int cnt = 10;
  6   while(cnt>=0)
  7   {
  8   printf("%2d\r",cnt);
  9   fflush(stdout);
 10   cnt--;
 11   sleep(1);
 12   }
 13   printf("\n");       // 回车的作用为使得倒计时的命令行不被覆盖掉                                                                            
 14  // printf("hello world"); // 1
 15  // fflush(stdout);
 16  // sleep(2);   //2
 17   return 0;
 18 }

如果我们想要修改为左对齐,只需要加上负号!

printf("%-2d\r",cnt);

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

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

相关文章

图观 | 嬴图GraphRAG在博物馆文物馆藏中的应用探讨

图数据库技术是AI走向强人工智能的必经之路和重器&#xff01;因为图数据库&#xff08;含知识图谱&#xff09;最大限度还原&#xff08;模拟&#xff09;了人的思维和思考方式。 —— 摘自孙宇熙《图数据库原理、架构与应用》 前言&#xff1a; 博物馆文物馆藏管理和观众服务…

基于内地城市生活垃圾收运场景的路线规划算法

基于混合遗传算法和模拟退火算法的优化垃圾收集路线规划 摘要 本论文提出了一种基于混合遗传算法&#xff08;GA&#xff09;和模拟退火算法&#xff08;SA&#xff09;的创新路线规划方法&#xff0c;旨在优化内地城市的生活垃圾收集效率。算法结合了遗传算法的全局搜索能力…

中证500etf期权合约一手多少钱?

中证500etf期权合约一手需要的资金取决于多个因素&#xff0c;比如做一手需要几十块钱到几百块钱不等&#xff0c;不过买卖中证500etf期权合约一手多少钱&#xff0c;也是包括期权的执行价格、权利金、保证金要求等。下文为大家介绍中证500etf期权合约一手多少钱&#xff1f;本…

.\venv\Scripts\activate : 无法加载文件 E:\,因为在此系统上禁止运行脚本。

问题描述&#xff1a; 问题原因&#xff1a; Windows PowerShell 的执行策略用于控制脚本的运行权限和安全性。 以下是几种常见的执行策略及其特点&#xff1a; AllSigned&#xff1a;只允许运行经过数字签名的脚本。这意味着无论是本地创建的还是从网络获取的脚本&#xff0…

如何设计一个高性能的分布式系统?

本文讨论的主题是高性能&#xff0c;主要思路是围绕快展开&#xff0c;这么设计为什么会快&#xff1f; 文章目录 架构设计&#xff1a;微服务架构负载均衡数据一致性方案选择容错处理&#xff1a;双机互备消息队列缓存总结 架构设计&#xff1a;微服务架构 第一个设计是应用…

“再来一单“业务功能开发

文章目录 概要整体架构流程技术细节小结 概要 再来一单”功能常见于餐饮、零售、外卖等行业&#xff0c;主要目的是为了简化用户的重复购买流程&#xff0c;提高用户体验和效率。 需求分析以及接口设计 再来一单就是将原订单中的商品重新加入到购物车中,所以本质上是"增…

人工智能助力芯片半导体发展,开拓芯片设计技术新趋势

微型硅片上可以容纳多少个晶体管&#xff1f;这些晶体管是构成世界各地技术的集成电路&#xff08;IC&#xff09;的基础。1971年&#xff0c;第一款微处理器集成有2,300个晶体管&#xff0c;而如今的硅片上却超过了1000亿个晶体管。在摩尔定律失效之前&#xff0c;每两年晶体管…

10、billu-b0x2

难度 中 目标 root权限 首先确定靶机ip地址 netdiscover -i eth0 -r 192.168.189.0/24 kali 192.168.189.58 靶机 192.168.189.184 信息收集端口扫描 看到一个80和8080&#xff0c;先重点摸一下网站的内容 然后看到信息里有个robots.txt 首先就去访问一下 看到有许多不允许…

高频JMeter软件测试面试题

近期&#xff0c;有很多粉丝在催更关于Jmeter的面试题&#xff0c;索性抽空整理了一波&#xff0c;以下是一些高频JMeter面试题&#xff0c;拿走不谢~ 一、JMeter的工作原理 JMeter就像一群将请求发送到目标服务器的用户一样&#xff0c;它收集来自目标服务器的响应以及其他统计…

传统产品经理VS现在AI产品经理,你要学习的太多了,超详细收藏我这一篇就够了

传统产品经理想要转行成为AI产品经理&#xff0c;需要经历一系列的学习和实践过程。下面是一份详细的学习路线图&#xff0c;旨在帮助你顺利转型。 学习路线图 了解AI基础知识 AI概览&#xff1a;阅读《人工智能&#xff1a;一种现代的方法》这样的书籍&#xff0c;以获得对AI…

初谈Linux多线程--线程控制

文章目录 线程的概述理解线程Linux中的线程重新理解的进程Windows的线程线程的优点线程的缺点理解线程调度成本低 进程VS线程 线程控制创建线程等待线程线程函数传参线程的返回值新线程的返回值新线程返回值错误返回值为类对象 创建多线程线程的终止线程的分离pthread_detach 线…

AIExpo2024奖项申报正式启动,三大奖项为你闪耀

由新一代人工智能产业技术创新战略联盟、苏州市人工智能协同创新中心联合主办&#xff0c;苏州启智创新科技有限公司、苏州工业园区科技发展有限公司共同承办的第六届全球人工智能产品应用博览会&#xff08;以下简称“智博会”&#xff09;将于2024年9月11-12日在苏州国际博览…

二叉搜索树,Map,Set,LeetCode刷题

二叉搜索树&#xff0c;Map&#xff0c;Set 1. 二叉搜索树2. 二叉搜索树的模拟实现1.1 插入操作1.2 查找操作1.3 删除操作 3. 二叉搜索树时间复杂度分析4. TreeMap和TreeSet5. Map5.1 Map的常用方法5.2 Map.Entry<K,V> 6. Set6.1 Set的常用方法 LeetCode刷题1. 二叉搜索树…

Total Eclipse 挑战赛:在以太坊首个 SVM L2 上开发应用

摘要&#xff1a;Eclipse 基金会宣布了其首届黑客马拉松计划&#xff0c;即"The Total Eclipse Challenge"&#xff0c;作为一场独一无二的黑客松活动 &#xff0c;邀请了优秀的开发者们在链上开发创新的应用。 "The Total Eclipse 挑战赛" 是一项为期两周…

如何更好地做出判断?

笛卡尔有句名言&#xff1a;无法下判断的人&#xff0c;不是欲望太奢侈&#xff0c;就是觉悟还不够。 这里说的判断&#xff0c;其实也就是选择。我们人生面临着各种维度的选择&#xff0c;大到人生方向&#xff0c;小到一顿饭吃什么&#xff0c;可以说&#xff0c;选择伴随着我…

全志T113i移植LAN8720指南

1、根据硬件修改设备树 gmac0_pins_a: gmac0 {allwinner,pins "PG0", "PG1", "PG2", "PG3", "PG4","PG5", "PG11", "PG12", "PG13", "PG14", "PG15";allwin…

vue3+TS+nest+mysql实现网站访问统计系统

网站采用了vue3tsnestmysql的技术选型&#xff0c;目前初步实现第一版开发 访问地址&#xff1a;点我进入网站 网站访问统计 主要通过插入script来调用上传接口来实现数据统计,目前仅存储了用户的ip和访问时间&#xff0c;后期也可根据ip来获取用户的城市信息 async pageUplo…

探索TinyDB的轻量级魅力:Python中的微型数据库

文章目录 探索TinyDB的轻量级魅力&#xff1a;Python中的微型数据库背景&#xff1a;为何选择TinyDB&#xff1f;什么是TinyDB&#xff1f;如何安装TinyDB&#xff1f;5个简单的库函数使用方法3个场景下的应用实例常见问题与解决方案总结 探索TinyDB的轻量级魅力&#xff1a;Py…

社区志愿服务管理平台小程序/社区志愿者管理系统

获取源码联系方式请查看文章结尾&#x1f345; 摘 要 随着当今网络的发展&#xff0c;时代的进步&#xff0c;各行各业也在发生着变化&#xff0c;于是小程序也逐步进入人们的生活&#xff0c;给我们生活或者工作提供了新的方向新的可能。 本毕业设计的内容是设计实现一个基…

芯片解密技术可以应用在哪些领域?

芯片解密技术可以在以下一些领域得到应用&#xff1a; 电子产品维修&#xff1a;对于一些老旧或难以获取原厂技术支持的设备&#xff0c;通过解密芯片获取程序代码可以更有效地进行故障诊断和维修。技术研究和学习&#xff1a;帮助科研机构和技术人员深入了解先进芯片的设计和工…