当前位置: 首页 > news >正文

Linux:自动化构建 - make

Linux:自动化构建 - make

    • make基本概念
    • makefile语法
      • 变量
      • PHONY


make基本概念

make是一个用于自动化编译和构建过程的工具。它主要用于管理大型软件项目的构建过程,帮助开发者更高效地编译和部署代码,并减少人为错误的发生,这使得软件的编译和部署变得更加自动化和可靠。

其中make是一个命令,执行该命令需要当前操作目录下有一个名为makefile或者Makefile的文件,在makefile内部编写指令,随后就可以通过make快速执行一系列的指令了。

当前目录下有一个test.c文件,需要把该文件编译为可执行文件mybin。该过程就可以用make来自动执行。我先编写一个makefile,然后再讲解,代码如下:

mybin:test.cgcc -o mybin test.c
clean:rm -f mybin   

其中我们可以看到两条熟悉的指令:gcc -o mybin test.c,该指令完成把test.c文件编译为可执行文件mybinrm -f mybin,该指令完成对mybin的删除。

有了这个文件后,我们就可以直接输入make,完成对test.c的编译:

在这里插入图片描述

一开始目录下只有makefiletest.c两个文件,执行指令make后,Linux自动执行了指令gcc -o mybin test.c,最后目录中就出现了编译好的可执行文件mybin

我们也可以输入make clean,完成对mybin的删除:

在这里插入图片描述

执行make clean后,Linux自动执行了指令rm -f mybin,完成了mybin的删除。

看到其大致是如何执行后,我现在讲解以上代码中各个部分的作用是啥。

mybin:test.cgcc -o mybin test.c
  • mybin:test.c:这个由两个文件名通过一个:隔开的整体,叫做依赖关系。左侧的mybin叫做目标文件,右侧的test.c叫做依赖文件列表
  • gcc -o mybin test.c:这个语句叫做依赖方法

那么依赖关系目标文件依赖文件列表依赖方法之间有什么关系呢?

  1. 目标文件:

    • 目标文件是 make 命令要生成的文件,通常是可执行程序、库文件或中间目标文件。
    • 每个目标文件都有一条或多条命令来生成它。
    • 目标文件可以有多个依赖文件,这些依赖文件共同决定了目标文件的生成过程。
  2. 依赖文件列表:

    • 依赖文件列表描述了目标文件所依赖的输入文件,如源代码文件、头文件、库文件等。
    • 依赖文件列表告诉 make 哪些文件的变化会导致目标文件需要重新生成。
    • 依赖文件列表可以包含多个文件,用空格分隔。
  3. 依赖关系:

    • 目标文件与其依赖文件之间形成依赖关系。
    • 如果依赖文件中任何一个文件发生变化,目标文件就需要重新生成。
    • 依赖关系可以形成层次结构,实现文件之间的层次依赖。
  4. 依赖方法:

    • 依赖方法是生成目标文件所需执行的命令。
    • 依赖方法通常是 shell 命令,用于编译、链接等操作。
    • 依赖方法可以包含多条命令,每条命令用回车分隔。

这里要注意,依赖方法前面必须用一个Tab键隔开,不可以是四个空格。

再看到后半段:

clean:rm -f mybin   

该代码中,目标文件是clean,没有依赖文件列表,依赖关系是删除mybin的指令。只要执行make clean就会执行后面的代码rm -f mybin ,从而实现文件的删除。

左侧的目标文件clean叫做伪目标伪目标是 make 中的一种特殊目标,它不对应任何文件,只是用来执行一些命令。常见的伪目标有 all、clean、install 等。

那么现在有一个问题,为什么执行mybin:test.c直接使用make就可以,但是make clean才能执行clean呢?

make后面不接任何内容时,则在makefile中从上往下查找,找到第一个依赖关系执行

现有如下makefile

mybin:test.ogcc -o mybin test.o
test.o:test.sgcc -c -o test.o test.s
test.s:test.igcc -S -o test.s test.i
test.i:test.cgcc -E -o test.i test.cclean:rm -f test.i test.s test.o mybin

该文件完成了一个连续的C语言程序编译链接过程,但是其有一个问题在于,C语言编译过程应该依次生成.i.s.o文件,最后生成mybin。第一条依赖关系执行的时候,就缺少test.o文件,第二条依赖关系缺少test.s文件,以此类推,整个编译过程都是反的。那么该makefile可以执行成功吗?

我们试试:

在这里插入图片描述
可以看到,其执行成功了,这是为什么?我只输入了make指令,按理来说应该只执行第一条依赖关系,为什么除了clean的所有依赖关系都被执行了?

make会根据文件的依赖关系进行自动推导,以正确的顺序执行各个依赖关系

比如说一开始mybin缺少了test.o,于是makemakefile中查找,发现test.o:test.s的依赖关系可以生成test.o于是先执行该依赖关系。但是test.o:test.s的依赖关系缺少test.s,就再去找生成test.s的依赖关系,以此类推。


makefile语法

以上我们只简单讲解了一个基本的makefile例子,来帮助大家理解make,现在我们来讲解更多的makefile语法。

首先,在makefile中,指令内部的目标文件可以用$@代替,依赖文件列表可以用$^代替:

mybin:test.cgcc -o $@ $^  

在这里gcc -o $@ $^ gcc -o mybin test.c 是一样的。

变量

makefile中,是可以定义变量的,只需要用一个等号进行赋值即可:

bin=mybin
src=test.c

此时bin的值就是mybinsrc的值就是test.c,想要使用这个变量,就在对应的地方以$(变量名)的形式代替即可,这个变量可以放在任何地方,包括指令内部,依赖关系中等等。

比如下面这样:

bin=mybin
src=test.c$(bin):$(src)gcc -o $(bin) $(src)clean:rm -f $(bin)

任何需要test.cmybin的地方,都可以改为$(bin)$(src)


PHONY

讲解PHONY前,我们看到一个问题:

在这里插入图片描述
现在我们每次make都会生成一个mybin文件,如果直接gcc -o mybin test.c,那么新生成的mybin文件会覆盖原先的文件。但是make执行的指令,会进行一次检查,如果源文件test.c没有进行更新,那么make就会拒绝再次编译这个文件,因为编译出来的结果是一样的,导致mybin无法连续编译两次。

也就是上图中我们连续两次make,第二次拒绝了我们的原因。

PHONYMakefile中是一个非常有用的特殊目标。make执行到PHONY目标时,它会无条件执行该目标下定义的命令,而不会检查是否有同名的文件在

因此我们就可以对mybin使用这个PHONY,让它强制执行命令,不论当前目录下有没有mybin

修饰语法:

.PHONY:xxx

此时xxx对应的命令就会被强制执行。

makefile写法:

.PHONY:mybin
mybin:test.cgcc -o mybin test.c

此时mybin每次都会强制执行命令,不论之前是否存在mybin文件了。

但是这并不是PHONY的主要用途,其主要用于修饰伪目标。比如伪目标clean,如果当前目录下刚好有一个叫做clean的文件,那么clean作为一个目标文件,就有可能会被make禁止执行。可是我们的clean作为一个伪目标,其目的不是生成一个clean文件,而是执行命令,因此要用PHONY来强制执行clean对应的命令:

.PHONY: clean
clean:rm -rf *.o

在这里,clean是一个PHONY目标,即使当前目录下有一个名为clean的文件,make clean也会执行删除操作,而不是试图构建clean文件。


相关文章:

  • 全国水科技大会 免费征集《水环境治理减污降碳协同增效示范案例》
  • 使用阿里云试用Elasticsearch学习:2.1 深入搜索——结构化搜索
  • 解决前端笔记本电脑屏幕显示缩放比例125%、150%对页面大小的影响问题
  • Vite 项目中环境变量的配置和使用
  • 如何判断服务器的线路
  • 【通过虚拟现实:让我们对危险更敏感】
  • Win11 使用 WSL2 安装 linux 子系统 ubuntu
  • 虚幻引擎启动报错记录
  • 如何使用 React 构建跑马灯组件
  • 6种xinput1_3.dll丢失的解决办法,并探讨xinput1_3.dll丢失的原因及其属性。
  • Harmony鸿蒙南向驱动开发-MIPI DSI
  • HTTP与HTTPS:深度解析两种网络协议的工作原理、安全机制、性能影响与现代Web应用中的重要角色
  • Spring Boot 整合 Apache Phoenix 进行 HBase 数据操作指南
  • Prime (2021): 2
  • 黑白图像彩色化
  • Fundebug计费标准解释:事件数是如何定义的?
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • Python语法速览与机器学习开发环境搭建
  • session共享问题解决方案
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 给github项目添加CI badge
  • 今年的LC3大会没了?
  • 那些年我们用过的显示性能指标
  • 设计模式走一遍---观察者模式
  • kubernetes资源对象--ingress
  • 关于Android全面屏虚拟导航栏的适配总结
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • # 睡眠3秒_床上这样睡觉的人,睡眠质量多半不好
  • #《AI中文版》V3 第 1 章 概述
  • #vue3 实现前端下载excel文件模板功能
  • (8)STL算法之替换
  • (9)目标检测_SSD的原理
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (第61天)多租户架构(CDB/PDB)
  • (附程序)AD采集中的10种经典软件滤波程序优缺点分析
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (收藏)Git和Repo扫盲——如何取得Android源代码
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (转)IIS6 ASP 0251超过响应缓冲区限制错误的解决方法
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)Spring4.2.5+Hibernate4.3.11+Struts1.3.8集成方案一
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网
  • *_zh_CN.properties 国际化资源文件 struts 防乱码等
  • .NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃
  • .NET Micro Framework初体验
  • .net 生成二级域名
  • .NET中使用Redis (二)
  • .sh 的运行
  • @data注解_一枚 架构师 也不会用的Lombok注解,相见恨晚
  • [ vulhub漏洞复现篇 ] JBOSS AS 4.x以下反序列化远程代码执行漏洞CVE-2017-7504
  • [ANT] 项目中应用ANT
  • [Hadoop in China 2011] Hadoop之上 中国移动“大云”系统解析
  • [IE编程] 如何在IE8 下调试BHO控件/工具栏(调试Tab进程)
  • [Kubernetes]4. 借助腾讯云TKE快速创建Pod、Deployment、Service部署k8s项目