Linux | makefile简单教程 | Makefile的工作原理

前言 

在学习完了Linux的基本操作之后,我们知道在linux中编写代码,编译代码都是要手动gcc命令,来执行这串代码的。

 但是我们难道在以后运行代码的时候,难道都要自己敲gcc命令嘛?这是不是有点太烦了?

 在vs中,我们编写好代码之后,直接点击构建项目,就会直接帮我们自动化构建好了,我们在linux中构建的时候,有的时候上百个文件,还是比较麻烦的,所以到底有没有一些简单的做法呢?当然是有的啦~

这个工具呢就是Makefile/make项目自动化构建工具

  • 会不会写Makefile,从一个侧面说明了一个人是否具有完成大型工程的能力;
  • 一个工程的源文件不计其数,其按类型、功能、模板分别放在一个若干个目录中,Makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作;
  • Makefile带来的好处就是——自动化编译。一旦写好,只需要一个make命令,整个工程就完成自动化编译,极大提高了软件开发的效率;
  • make是一个命令工具,是一个解释Makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,visual C++的make,linux下GNU的make。可见,Makefile都成为了一种在工程方面的编译方法。
  • make是一个命令,Makefile是一个文件,两个搭配使用,完成项目自动化构建

实例理解

 在上图中,mytest:text.cgcc -o mytest test.c是匹配的,clean:rm -f mytest是匹配的。这两组中的每个第一句是依赖关系,两组的下面称为依赖方法

Makefile实现原理

以图为例(与上图例子一致,为了方便大家查看,就在下面也放一份):

 Makefile文件写好之后,当我们实际在命令行运行make的时候,对应的make程序,会在当前目录下找这个Makefile,读取Makefile里面的内容:

  • make会根据Makefile里面的内容,完成编译、清理工作。
  • 根据Makefile里面的依赖关系,依赖关系依赖方法形成目标文件

(如上图:编译器就会知道依赖关系test.c文件形成mytest的目标文件,那么怎么形成呢?就是根据对应的gcc -o mytest test.c这样的依赖方法)

依赖关系

那么到底如何理解依赖关系依赖方法呢?

这里就给大家将一个小故事咯~便于大家理解:

小明是某大学里的在校生,这天他没有生活费了。他就打电话给那个人:“爸!我是你儿子!”在小明看来,你是我爸你就应该给我生活费;但是在老爹看来,你小子说这话是啥意思?你想干啥?老爹是一脸懵啊。小明挂了电话之后,就又想了想:“爸!我是你儿子!给我点生活费!”这下他老爹才懂了,原来他儿子没有生活费了,想要生活费。

所以在上面的小故事中,“我是你儿子”就是依赖关系,“给我点生活费”就是依赖方法。在日常生活中,我们也难免得需要拜托谁做一件什么事,在计算机中也是一样的,完成一件事的必然要素少不了依赖关系与依赖方法。

在上图中的依赖关系如下:

其实,我们知道程序翻译运行的过程为:预处理、编译、汇编和链接。

翻译的过程

gcc命令

说明

预处理

(进行宏替换)

gcc -E test.c -o test.i

-E 让gcc在预处理结束后,就停止编译

“从现在开始进行程序的翻译,预处理完成,就停下来”

宏替换

去注释

头文件展开

条件编译

生成.i文件

编译

(生成编译)

gcc -S test.i -o test.s

-S 只进行编译不进行汇编,生成汇编代码

“从现在开始进行程序的编译,汇编完成就停下来”

检查代码规范性

检查语法错误

(确认无误后汇编)

C语言代码翻译成汇编语言

生成.s文件

汇编

gcc -C test.o -o test.o

-C “从开始带现在进行程序的翻译”,汇编完成就停下来

将汇编语言编译成二进制目标文件

生成.o文件

链接

gcc test.o -o my.exe

形成可执行程序

生成.exe文件

所以将上面gcc -o mytest test.c指令写完整就是如下:

诶?很奇怪啊,怎么感觉顺序呢不太对?在这里我们就要说一下Makefile的工作原理了:

  • Makefile在执行过程中,是从上往下进行扫描的;
  • 当它看到的第一个文件时,其实并不是.c文件,第一个是.o文件;
  • 也就是识别的从上往下,第一组依赖关系;
  • 可是识别的依赖关系中的.o文件并不存在,所以它下面的命令,也就是依赖方法不能被执行,就无法形成可执行程序;
  • 所以Makefile就会自动在后续,继续再找下一组依赖关系,根据下一组依赖关系来形成.o文件;
  • 但是在形成.o文件还是需要依赖.s文件,依次类推直到遇到依赖文件存在.c文件;
  • 所以存在.c文件,就会有.i文件、.s文件以及.o文件;
  • 所以就下往上执行了,很类似与递归问题。

在上图中:

  • 上面的文件 mytest ,它依赖 mytest.o
  • mytest.o , 它依赖 mytest.s
  • mytest.s , 它依赖 mytest.i
  • mytest.i , 它依赖 mytest.c
  • make、Makefile会自动根据文件中的依赖关系,进行自动推导,帮助我们执行所有相关的依赖方法。

这里注意一下,因为Makefile就是类似于一个选择器,里面包含了各种指令的选项,但是一般默认智慧运行第一个依赖关系所对应的指令,所以上面的各组依赖关系是可以乱序的,但是必须要将最重要的一条指令放在最前面,如下图:

 上面的依赖关系,是为了让大家能够理解,这里不建议大家写成这样,直接就gcc -o mytest test.c指令就可以。

依赖文件列表

依赖文件列表可以为多个文件,按照空格分割分。

mytest:依赖文件1 依赖文件2 依赖文件3 ...

 

我们刚刚也说了clean:rm -f mytest是匹配的。根据上图我们也不难看出,clean后面是空的,也就是说clean不依赖任何文件,也就是说:

  • 依赖文件列表可以为空。 

依赖方法

依赖方法的指令前必须打一个[Tab]键,按四下空格会报错。

多条依赖方法

  • 依赖方法不限于一条,可以是多条的。 

项目清理

.PHONY含义

在Makefile文件执行的时候,如下图,我们发现在使用make的时候默认执行的是Makefile文件中的第一对的依赖关系和依赖方法:

  • Makefile默认形成第一个可执行文件。

 其次,我们看下边运行过程:

make: `mytest' is up to date. :当前可执行程序是最新的。

  • 所以Makefile会在源代码的内容没有修改,没有变化时,Makefile默认就会拦截再一次的make命令。

那么如果今天我们就想让其一直执行,不要拦截,即使在没有被修改源码的情况下,也要让make指令一直执行,那么怎么做呢?只需要:

  • .PHONY : XXX 
  • XXX对应的方法总是要被执行的。

 当然我们理解了原理之后,小编还是建议大家之后再清理的命令加上总是可执行即可。所以我们目前标准的就是以下5行:

以后我们需要的Makefile文件

通配符认识

符号含义
$^所有依赖文件列表
$@所有目标文件
$<所有依赖文件的第一个文件

 在这里,我们可以将$,理解为取内容

如下图,gcc在编译的过程,Makefile会自动进行符号替换:

  • 把对应的$@就会自动替换为目标文件
  • 把对应的$^就会自动替换为所有依赖文件

变量

Makefile也是支持变量的。但是并不是之前学习的编程语言中的整形、浮点型int/double=1/1.0等等。Makefile是解释性的,所以它的变量直接就是符号,比如说,“‘形成的可执行程序’为‘XX’”:

  • bin是“目标文件可执行程序”的变量 ;
  • src是“依赖文件列表”的变量;
  • $可以理解为去内容;
  • $(bin):取出bin变量中的内容,即目标文件;
  • $(src):取出src变量中的内容,即依赖文件列表;
  • $@:所有的目标文件;
  • $^:所有的依赖文件列表。

在执行make的时候,Makefile就会进行变量替换,可以理解成为宏的替换,也可以执行程序。

将来你可能会有很多地方遇到使用make的项目与文件,那就只需要将变量的内容修改,就可以完成不同文件的make指令进行执行,就会很简单方便。

make指令打印隐藏

在命令行输入make指令之后,系统都会自己打印出我们底层所输入的依赖方法对应的指令,那么如何将make指令进行隐藏也就是让它不再打印呢?

直接在命令前面加一个“@”符号:

推荐使用的Makefile模板

bin=test.exe    
src=test.c      
    @gcc -o $@ $^
    @echo "compiler $(src) to $(bin)..."
.PHONY:clean
clean:
    @rm -f $(bin)
    @echo "clean project..."

  • 其中echo是打印字符串。 

如下图就会有提示信息:

必熟知知识

为什么Makefile对最新的可执行程序,默认不想重新形成?

今天,我们编译的代码只有一个源文件,以后我们编译的源代码是两千个源文件,成百上千个源文件,在我们修改bug的时候,可能只是修改几行代码,做完改动之后,如果我们要将所有的源文件重新编译一遍,那么就是效率很低,又或者说,如果我们没有修改,又make的话,那么编译器又会重新编译,假如一个文件需要用0.1秒,那么成百上千个代码就需要十几分钟甚至几个小时,所以效率是极其低的。

  • 所以在Makefile为了调高效率,就默认对最新的可执行程序,不重新形成。

Makefile怎么知道程序需要被编译的呢?

ACM时间是Linux系统下分别代表AccessModifyChange三个时间。

  • Access:文件最近被访问的时间(访问)
  • Modify : 文件内容最近被修改的时间(修改)
  • Change : 文件属性最近被修改的时间(改变)

当然我们要知道的是:

  • 源代码可执行程序文件内容最近被修改的时间(修改)一定是不同的。 

因为我们基本先写源代码,再进行编译;所以可执行程序一般是比源代码的时间更新的。如果修改的源代码,那么此时源代码比可执行程序的时间更新,所以就需要重新编译。

Makefile怎么知道程序需要被编译的呢?

  • 对比可执行程序的最近修改时间和源文件最近的修改时间,谁更新。如果可执行程序更新,就不需要重新编译了;反之,源文件更新,就需要重新编译。

所以我们在用vs写代码的时候,出现错误 ,再修改了很多次,仍旧报这个错误,这个时候,可以重新清理一下,重新构建一下,重新生成解决方案,这个问题就会可能解决。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

接口自动化测试:mock server之Moco工具

什么是mock server mock&#xff1a;英文可以翻译为模仿的&#xff0c;mock server是我们用来解除依赖&#xff08;耦合&#xff09;&#xff0c;假装实现的技术&#xff0c;比如说&#xff0c;前端需要使用某些api进行调试&#xff0c;但是服务端并没有开发完成这些api&#…

SAP 票据批导实现方法

增强结构定义 变量定义 调用bapi前处理相关变量

【JavaScript权威指南第七版】读书笔记速度

JavaScript权威指南第七版 序正文前言&#xff1a;图中笔记重点知识第1章 JavaScript简介第一章总结 第2章 词法结构注释字面量标识符和保留字Unicode可选的分号第二章总结 第3章 类型、值和变量【重要】原始类型特殊类型第三章总结 第4章 表达式与操作符表达式操作符条件式调用…

HTML-框架标签、实体、全局属性和元信息

HTML 1.框架标签 <iframe name"b站" src"https://www.bilibili.com" width"500" height"300" frameborder"0"></iframe>iframe 标签的实际应用&#xff1a; 在网页中嵌入广告。与超链接或表单的 target 配合&a…

林浩然的Java冒险:从单分支到多分支的奇趣编程之旅

林浩然的Java冒险&#xff1a;从单分支到多分支的奇趣编程之旅 Lin Haoran’s Java Adventure: A Whimsical Journey from Single Branch to Multiple Branches 在那个充满神秘色彩的Java编程世界里&#xff0c;林浩然是一位无畏的程序武士。他的江湖历险从单一的分支结构开始&…

链表的应用1--多项式求和

今天学数据结构学到的链表应用于多项式相加&#xff0c;但是书上的代码没看懂&#xff0c;在看了点资料和问ChatGPT以后想到的一个算法&#xff0c;后面有更好的想法在回来更新算法 1.链表相关结构&#xff1a; //链表结点结构 typedef struct linknode {int coef;//系数 int…

磁悬浮轴承行业调研:未来高端市场占比将有所提升

磁悬浮轴承是利用磁力作用将转子悬浮于空中&#xff0c;使转子与定子之间没有机械接触。其原理是磁感应线与磁浮线成垂直&#xff0c;轴芯与磁浮线是平行的&#xff0c;所以转子的重量就固定在运转的轨道上&#xff0c;利用几乎是无负载的轴芯往反磁浮线方向顶撑&#xff0c;形…

【C++修行之道】STL(初识pair、vector)

目录 一、pair 1.1pair的定义和结构 1.2pair的嵌套 1.3pair自带排序规则 1.4代码示例 二、vector 2.1vector的定义和特性 2.2vector的初始化 一维初始化&#xff1a; 2.3vector的常用函数 2.4vector排序去重 排序: 去重&#xff1a; 示例&#xff1a; 一、pair …

Argo CD 可观测性最佳实践

什么是 Argo CD&#xff1f; Argo CD 是一个开源的 CD&#xff08;Continuous Delivery&#xff09;工具&#xff0c;能够帮助您在 Kubernetes 环境中进行持续交付。Argo CD 的主要功能是将配置文件同步到 Kubernetes 集群中并确保应用程序正确运行。Argo CD 可以自动检测应用…

14.5 Flash查询和添加数据库数据

14.5 Flash查询和添加数据库数据 在Flash与数据库通讯的实际应用中&#xff0c;如何实现用户的登录与注册是经常遇到的一个问题。登录实际上就是ASP根据Flash提供的数据查询数据库的过程&#xff0c;而注册则是ASP将Flash提供的数据写入数据库的过程。 1.启动Access2003&…

代码随想录算法训练营29期|day31 任务以及具体安排

理论基础 关于贪心算法&#xff0c;你该了解这些&#xff01; 题目分类大纲如下&#xff1a; #算法公开课 《代码随想录》算法视频公开课 (opens new window)&#xff1a;贪心算法理论基础&#xff01; (opens new window),相信结合视频再看本篇题解&#xff0c;更有助于大家…

【构造方法】这或许是讲的最好的关于Java构造方法的文章!!

致读者 对于看到这篇博客的你们&#xff0c;其实不需要刻意的去记这些知识&#xff0c;可以收藏起来&#xff0c;有事没事翻开看看&#xff0c;这些其实看得多了&#xff0c;自然就烂熟于心了&#xff0c;如果你只是刻意的记忆了一遍&#xff0c;那其实你很快就会忘记&#xf…

仰暮计划|“以前老一辈农村人真的是穷极了……苦极了……”

仰暮计划|“以前老一辈农村人真的是穷极了……苦极了……” 回首往事&#xff0c;几十年的坎坷经历难以件件叙述&#xff0c;却又历历在目。以前老一辈农村人真的是穷极了……苦极了……我奶奶是1941年生人&#xff0c;用她的话说就是“命很硬”。我爷爷1940年生人&#xff0c;…

[TII 2023] 基于压缩感知的多级隐私保护方案

Multilevel Privacy Preservation Scheme Based on Compressed Sensing | IEEE Journals & Magazine | IEEE Xplore 摘要 物联网的广泛应用在给人们带来便利的同时&#xff0c;也引发了人们对数据采集、分析和共享过程中隐私泄露的担忧。本文提出了一种基于压缩感知的多级…

电商系统设计到开发03 引入Kafka异步削峰

一、前言 系统设计&#xff1a;电商系统设计到开发01 第一版设计到编码-CSDN博客 接着上篇文章&#xff1a;电商系统设计到开发02 单机性能压测-CSDN博客 本篇为大制作&#xff0c;内容有点多&#xff0c;也比较干货&#xff0c;希望可以耐心看看 已经开发的代码&#xff0…

【行业应用-智慧零售】东胜物联餐饮门店智能叫号解决方案,为企业智能化升级管理服务

随着科技的不断进步&#xff0c;物联网设备已经广泛应用于各行各业&#xff0c;包括餐饮业。在餐饮门店的线下运营过程中&#xff0c;叫号系统是一项重要的设备需求。传统的叫号方式往往会消耗大量的人力和时间&#xff0c;而物联网技术为餐饮行业提供了一种更高效、智能化的解…

幻兽帕鲁服务器数据备份

搭建幻兽帕鲁个人服务器&#xff0c;最近不少用户碰到内存不足、游戏坏档之类的问题。做好定时备份&#xff0c;才能轻松快速恢复游戏进度 这里讲一下如何定时将服务器数据备份到腾讯云轻量对象存储服务&#xff0c;以及如何在有需要的时候进行数据恢复。服务器中间的数据迁移…

【论文阅读】GraspNeRF: Multiview-based 6-DoF Grasp Detection

文章目录 GraspNeRF: Multiview-based 6-DoF Grasp Detection for Transparent and Specular Objects Using Generalizable NeRF针对痛点和贡献摘要和结论引言模型框架实验不足之处 GraspNeRF: Multiview-based 6-DoF Grasp Detection for Transparent and Specular Objects Us…

为什么TestNg会成为Java测试框架的首选?还犹豫什么,看它!

上一篇自动化测试我们大概了解了测试的目标、测试的技术选型以及搭建平台的目标及需求&#xff0c;也确定了自动化测试方案以testNg作为整个测试流程贯穿的基础支持框架&#xff0c;那么testNg究竟有什么特点&#xff1f;本篇开始我们来详细的学习testNg这个测试框架。 为什么要…

qwt直角坐标 画sing(x)/x

cmath的常见函数&#xff1a;qPow()求平方&#xff0c;log(&#xff09;对数10为底 角度转弧度&#xff1a;x(angel/180)*M_PI 图示&#xff1a; 头文件&#xff1a; #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <qwt_plot.h> #in…