【Linux】自动化构建工具-make/Makefile

个人主页 : zxctscl
如有转载请先通知

文章目录

  • 1. 前言
  • 2. 认识make/Makefile
  • 3. 了解make/Makefile原理
    • 3.1 依赖关系和依赖方法
    • 3.2 make检测的顺序
    • 3.3 PHONY:XXX
  • 4. makefile内置符号

1. 前言

在上一篇中已经了解了【Linux】编译器-gcc/g++使用,这次来一起看看make/Makefile。

2. 认识make/Makefile

make是一个命令
makefile是一个文件。

先touch一个makefile/Makefile(m大小写都可以)文件:
在这里插入图片描述
然后进入makefile写一段代码:
未来形成的可执行程序是mytest,依赖的是test.c。就是将test.c编译形成mytest的可执行程序。
在这里插入图片描述
直接make编译一下:
在这里插入图片描述
因为版本比较低,这里提示要加上-std=c99。重新打开makefile加上就行:
在这里插入图片描述

此时在重新make一下就有了:
会自动形成我们要的可执行程序mytest
在这里插入图片描述
在这里插入图片描述
如果想要清理编译产生的临时文件怎么办?
再次打开makefile:
在这里插入图片描述

退出后直接用命令清理一下

make clean

发现mytest已经没有了:
在这里插入图片描述

  1. makefile文件中,保存了编译器和链接器的参数选项,并且描述了所有源文件之间的关系。

    1. make程序会读取makefile文件中的数据,然后根据规则调用编译器,汇编器,链接器产生最后的输出。
  2. Makefile里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。
    显式规则说明了,如何生成一个或多个目标文件。

  3. make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写makefile,比如源文件与目标文件之间的时间关系判断之类

  4. 在makefile中可以定义变量,当makefile被执行时,其中的变量都会被扩展到相应的引用位置上,通常使用 $(var) 表示引用变量文件指示。包含在一个makefile中引用另一个makefile,类似C语言中的include;

  5. 注释,makefile中可以使用 # 在行首表示行注释

  6. 默认的情况下,make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件,

3. 了解make/Makefile原理

打开Makefile,来看看前面两行:
在这里插入图片描述
写好Makefile后,当我们实际是在运行make时候:对应的程序就会在当前程序找makefile,然后读取makefile里面的内容,根据依赖关系,知道test.c形成mytest这样的可执行程序,根据gcc写的依赖方法来执行。

make会根据makefile的内容,完成编译或者清理工作。

3.1 依赖关系和依赖方法

怎么理解依赖关系和依赖方法呢?

举个例子:在现实生活中求人办事,就先得和他们产生某种关系,然后才会有后面的方法。就像小明没有生活费了,向他父亲打电话,就说一句:我是你儿子。这个就表明了依赖关系。表明了依赖关系然后,小明想要做什么?所以小明重新打电话说:我是你儿子,没钱了,打点钱。就有了依赖方法。
计算机要形成某种可执行程序,就得先表明依赖关系,然后怎么具体形成可执行程序,这就要有具体依赖方法。

依赖关系和依赖方法是完成一件事情的必然要素,并非makefile特有的。

在这里插入图片描述
这里clean:是一种特殊的依赖关系,这个clean不依赖任何一个文件,是一种特殊情况。
所以说依赖文件列表可以为空。
在这里插入图片描述

3.2 make检测的顺序

在形成可执行程序的时候直接make就可以直接形成mytest,而不是执行clean?
要执行clean,就必须这样写make clean
在这里插入图片描述

也可以用make mytest这样去运行:
在这里插入图片描述
makefile它的运行推导规则是:默认从上到下,对makefile文件进行扫描,默认形成第一个目标文件。也就是只有make的时候,默认形成第一个目标文件。

如果把clean放在前面,那么默认先执行的就是clean:
在这里插入图片描述
发现直接make的时候先执行的clean:
在这里插入图片描述

默认将执行的可执行程序放在前面,这样make的时候就能直接形成了。
所以make检测的顺序是从上往下的

3.3 PHONY:XXX

当我们在程序里面不加上:在这里插入图片描述
在这里插入图片描述

来make一下后,在make一下,发现就不行了:
在这里插入图片描述
在程序不被修改时,make后,默认就不会在形成新的可执行程序,它认为没有必要。
如果想要makefile里面的操作总是被执行,不要因为是最新的就拦截,就加上:.PHONY:mytest
在这里插入图片描述
make多少次都会执行,没有拦截。
在这里插入图片描述

.PHONY:XXX

XXX对应的方法,总是要被执行。

一般可执行程序不需要.PHONY:修饰,但是我们总是希望clean重新清理。
默认将clean用.PHONY:修饰:
要然清理工作总是被执行。
在这里插入图片描述
在这里插入图片描述
为什么makefile对最新的可执行程序,默认不重新形成呢?
如果在一个项目里面存在上千个源文件,每次改代码时候,可能就修改一小部分。做了改动之后,如果每一次都把所以的源文件重新编译一遍,就会带来效率的延缓。还有可能出现在没有修改情况下,一编译就重新执行,上千个文件,在编译的时候又得重新编译,又得花费很长时间。既然形成的可执行程序都是新的,那么就不需要再重新编译。
就是为了提高编译效率

那么是怎么做到不重新执行的呢?换句话说makefile怎么知道我的程序需要被编译呢?

这里有一个Modify:文件的最新修改时间:
在这里插入图片描述
源代码和可执行程序最近一次形成或者修改的时间一定是不一样的。
每一次都是先写源代码再形成可执行程序。
最终要判断程序是否被编译:只要对比,可执行文件最近修改的时间和源文件最近修改的时间,谁更新。
可执行程序最新就不需要再编了,源文件最新就重新编译一下。

这里源文件没有更新,就不能再编译:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

来修改一下test.c的Modify时间:

touch test.c

在这里插入图片描述
make一下就又可以编了:
在这里插入图片描述

4. makefile内置符号

在这里插入图片描述

$:相当于取内容。
^:代表整个依赖文件列表,就是这里的code.c
@:代表目标文件,就是这里的code.exe

在编译的时候makefile会自动进行符号替换,把@替换为目标文件,^替换为code.c:
在这里插入图片描述
在这里插入图片描述

make之后,执行一下code.exe:
在这里插入图片描述

在把它清理掉:
在这里插入图片描述
在这里插入图片描述
把makefile如果要把它写全,就是这样的:
在这里插入图片描述
实际上编译器可以直接一步到位。
上面有4组依赖关系,就有依赖方法:

  1 code.exe:code.o2   gcc code.o -o code.exe -std=c993 code.o:code.s4   gcc -c code.s -o code.o -std=c995 code.s:code.i6   gcc -S code.i -o code.s -std=c997 code.i:code.c8   gcc -E code.c -o code.i -std=c99

在这里插入图片描述

在make后,在makefile里面写的代码重新编译了,编译后,依此形成了临时文件,并且形成了最终的可执行程序:

在这里插入图片描述
运行一下:
在这里插入图片描述

重新进入makefile:

  1 code.exe:code.o2   gcc code.o -o code.exe -std=c993 code.o:code.s4   gcc -c code.s -o code.o -std=c995 code.s:code.i6   gcc -S code.i -o code.s -std=c997 code.i:code.c8   gcc -E code.c -o code.i -std=c999 .PHONY:clean10 clean:11   rm -f code.i code.s code.o code.exe

在这里插入图片描述
此时code.i code.o code.s code.exe都被清理了:
在这里插入图片描述
在这里插入图片描述
发现执行的顺序和makefile里面代码顺序是相反的。
在这里插入图片描述
make拿到makefile文件时候,从上往下扫描,先看到的文件是code.exe,先识别的依赖关系是code.exe:code.o,但是发现code.o并不存在,所以 gcc code.o -o code.exe -std=c99是不执行的。
然后继续找下一组依赖关系:code.o:code.s,发现code.s并不存在,所以不执行这个依赖方法。
一直这样找,直到code.i:code.c,这个code.c是存在的,那么就会执行这一组依赖关系的依赖方法: gcc -E code.c -o code.i -std=c99。那么就形成了code.icode.i形成了,再回到code.s:code.i执行他的依赖方法gcc -S code.i -o code.s -std=c99。一直像这样,直到形成code.exe

makefile/make 会自动根据文件中的依赖关系,进行自动推导,帮助我们执行所有相关的依赖方法。

这些依赖关系就像栈一样,出栈执行方法:
在这里插入图片描述

如果注释调最后一组依赖关系:
在这里插入图片描述
就会出现没有规则去制作code.icode.i不存在,那么code.s也就不存在。
在这里插入图片描述

如果乱序排这些依赖关系:
在这里插入图片描述
能正常执行:
在这里插入图片描述

那么如果让第一个依赖关系放在后面呢:
在这里插入图片描述
此时make就不能执行:
在这里插入图片描述
因为makefile必须把最重要的文件放在前面,总的有个开头。一定要保证最终实现的目标文件是第一个。

那么之后我们写makefile就要这样写吗?
其实没有必要这样写。直接这样写就行:

  1 bin=code.exe2 src=code.c34 $(bin):$(src)5   gcc -o $@ $^ -std=c996 .PHONY:clean7 clean:8   rm -f $(bin)

在这里插入图片描述
这样也是可以执行的:
在这里插入图片描述

在这里插入图片描述
这里定义的变量就相当于宏。要改形成的可执行程序,就只改前面这两行的文件名就行。
举个例子:
在这里插入图片描述
重新make一下:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
如果不想在执行命令的时候出现提示出像下面这样的命令的内容:
在这里插入图片描述

在这里插入图片描述
不想显示出这些命令,那么就在这些命令前面加上@:
在这里插入图片描述
此时发现已经不显示了:
在这里插入图片描述

一般我们所使用不仅仅只有一个依赖方法,可以继续往后跟:
在这里插入图片描述

在这里插入图片描述
有问题请指出,大家一起进步!!!

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

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

相关文章

Arch xfce桌面修改中文locale为英文locale和i3wm禁用触摸板

中文很烦人,要切换输入法,所以更改 localectrl list-locales localectl set-locale en_US.UTF-8 localectl status另外有一个可替代的输入法方案: fcitx5 自行搜fcitx5 archwiki 重启,提示修改目录为英文,保留英文 i3wm 禁用触…

具有功耗低、触控灵敏度高、抗干扰能力强等功能的单键电容式触控芯片——TS223B,适用于小家电、电子玩具等产品

•应用领域• 适用于小家电、电子玩具、智能物联网等各种触控产品方案。 •功能介绍• 这款推出的单键电容式触控芯片TS223B具有功耗低、触控灵敏度高、抗干扰能力强等众多优势,输出方式包括直接输出、电平翻转输出,并且输出的初始状态可以配置&#xff…

前端将两个div在一个长为500px,高为300px的div里面并列居中对齐。

前端将两个div在一个长为500px&#xff0c;高为300px的div里面并列居中对齐。 要实现将两个 div 元素放置在一个长为500px&#xff0c;高为300px的父 div 中&#xff0c;一个在左边&#xff0c;一个在右边&#xff0c;并且居中对齐&#xff0c;可以使用Flexbox布局来实现。 <…

Vue快速教程:如何优雅地移除数组中的特定元素?

1、事件参与角色介绍 角色&#xff1a; 1、记录数组multipleSelection&#xff0c;负责记录目前已勾选的记录 2、表格变量currentDeviceList&#xff0c;显示显示当前表格的内容2、事件关联 由于表格是带筛选功能的&#xff0c;且记录带有记忆性&#xff0c;所以记录数组mul…

Outlook邮箱后缀是什么?如何改邮箱后缀?

Outlook邮箱后缀可以更改吗&#xff1f;微软有哪些后缀的邮箱&#xff1f; 对于许多刚接触Outlook邮箱的新手来说&#xff0c;了解Outlook邮箱后缀是必不可少的一步。那么&#xff0c;Outlook邮箱后缀究竟是什么呢&#xff1f;接下来&#xff0c;AokSend就来详细探讨一下这个问…

SSD203D高性能HDMI投影仪方案

一、方案描述&#xff1a; SSD203D是高度集成的高性能HDMI投影仪解决方案,主芯片为ARM Cortex A7,dule core,1.2GHz;内置DDR3,1Gb;支持H.264/H.265解码;支持JPEG基线编码;支持2D图形引擎;支持HDMI输出最高可达1920x1080/1920x120030fps ;支持SPI-Nor/Nand Flash;Built-in RTC;…

C语言之计算某日是该年的第几天

目录 一 简介 二 代码实现 三 时空复杂度 一 简介 在C语言中&#xff0c;计算某日是该年的第几天通常涉及以下步骤&#xff1a; 判断输入的年份是否为闰年。根据判断结果&#xff0c;确定当年二月的天数&#xff08;28或29天&#xff09;。然后&#xff0c;根据月份从前…

媒体邀约专访的意义?怎么做

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体邀约专访是指企业、组织或个人主动邀请媒体进行专题访谈的一种公关活动。这种活动对于提升品牌形象、传播信息、增强公众认知度和信任度等方面都有重要作用。以下是媒体邀约专访的一…

java生成水印图片

直接上代码&#xff1a; package com.hx.manage;import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException;/*** 管理端API-应用启动类** author EastHill*/ public class Main {public stat…

机器学习 - PyTorch使用流程

通常的 PyTorch Workflow 是这样的. But the workflow steps can be repeated and changed depending on the problem you’re working on. Get data ready (turn into tensors)Build or pick a pretrained model to suit your problem 2.1 Pick a loss function & optimi…

第1章 初识 Python 背记手册

1、print()—输出 print()函数的基本用法如下&#xff1a; print("输出的内容")其中&#xff0c;输出内容可以是数字和字符串&#xff08;使用引号括起来&#xff09;&#xff0c;此类内容将直接输出&#xff0c;也 可 以是包含运算符的表达式&#xff0c;此类内容…

彻底学会系列:一、机器学习之梯度下降(2)

1 梯度具体是怎么下降的&#xff1f; ∂ J ( θ ) ∂ θ \frac{\partial J (\theta )}{\partial \theta} ∂θ∂J(θ)​&#xff08;损失函数&#xff1a;用来衡量模型预测值与真实值之间差异的函数&#xff09; 对损失函数求导&#xff0c;与学习率相乘&#xff0c;按梯度反方…

马斯克AI大模型Grok开源了!

2024年3月18日&#xff0c;马斯克的AI创企xAI兑现承诺&#xff0c;正式发布了此前备受期待大模型Grok-1。 代码和模型权重已上线GitHub: https://github.com/xai-org/grok-1 截止目前&#xff0c;Grok已经在GitHub上获得了35.2k颗Star&#xff0c;还在不断上升中。 Grok官方博…

yolov9目标检测可视化图形界面GUI源码

该系统是由微智启软件工作室基于yolov9pyside6开发的目标检测可视化界面系统 运行环境&#xff1a; window python3.8 安装依赖后&#xff0c;运行源码目录下的wzq.py启动 程序提供了ui源文件&#xff0c;可以拖动到Qt编辑器修改样式&#xff0c;然后通过pyside6把ui转成python…

【11】工程化

一、为什么需要模块化 当前端工程到达一定规模后,就会出现下面的问题: 全局变量污染 依赖混乱 上面的问题,共同导致了代码文件难以细分 模块化就是为了解决上面两个问题出现的 模块化出现后,我们就可以把臃肿的代码细分到各个小文件中,便于后期维护管理 前端模块化标准…

Cookie、Session、Token详解及基于JWT的Token实现的用户登陆身份认证

目录 前置知识 Cookie 什么是Cookie Cookie的作用 Cookie的声命周期 Session 什么是Session 服务集群下Session存在的问题 集群模式下Session无法共享问题的解决 Cookie和Session的对比 Token 什么是Token 为什么产生Token 基于JWT的Token认证机制 Token的优势 …

第112讲:Mycat实践指南:字符串Hash算法分片下的水平分表详解

文章目录 1.字符串Hash算法分片的概念1.1.字符串Hash算法的概念1.2.字符串Hash算法是如何将数据路由到分片节点的 2.使用字符串Hash算法分片对某张表进行水平拆分2.1.在所有的分片节点中创建表结构2.2.配置Mycat实现字符串Hash算法分片的水平分表2.2.1.配置Schema配置文件2.2.2…

Redis Pub/Sub: 实时消息传递的完美解决方案

Redis发布订阅&#xff08;Pub/Sub&#xff09;是一种消息传递模式&#xff0c;允许消息的发送者&#xff08;发布者&#xff09;将消息发送给多个接收者&#xff08;订阅者&#xff09;。在Redis中&#xff0c;发布者和订阅者之间通过频道&#xff08;Channel&#xff09;进行…

算法刷题day33

目录 引言一、动态网格二、画图三、扫雷 引言 这几天一直再写关于搜索的问题&#xff0c;我发现搜索不仅仅局限于网格中的那种搜索&#xff0c;还有状态的变换&#xff0c;也可以抽象成一个点&#xff0c;去找最小变换次数&#xff0c;这也是一种搜索&#xff0c;所以说还是得…

SpringData JPA 快速入门案例详解

SpringData JPA JPA 简介&#xff1a; JPA&#xff08;Java Persistence API&#xff09;是 Java 持久层规范&#xff0c;定义了一些列 ORM 接口&#xff0c;它本身是不能直接使用的&#xff0c;因为接口需要实现才能使用&#xff0c;Hibernate 框架就是实现 JPA 规范的框架。…