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

自动化构建工具:makemakefile

在Windows中,我们写C代码或者C++代码都需要用先找到一款合适的编译器,用来方便我们更好的完成代码,比如说vs2019,这些工具的特点是集成了多种开发所需的功能,如代码编辑、编译、调试、版本控制等,无需在不同的工具之间切换。自动化和简化了许多常见的开发任务,减少了繁琐的操作和配置。像 Visual Studio 可以自动完成代码补全、语法检查,快速定位错误,节省了开发者的时间。
而在Linux中,我们也有一个工具不用再单纯的用gcc指令来运行代码,具体情况可以看上一篇博客。而这个工具就是make,虽然不像其他编译器那样快捷,美观。但是对于Linux系统开发来说,极大的提高了开发效率。

make和makefile概念

会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。现在我们就来学习这个工具。
make概念
在 Linux 中,make 是一个工具,用于自动化编译和构建软件项目,执行该命令需要当前操作目录下有一个名为makefile或者Makefile的文件,在makefile内部编写指令,随后就可以通过make快速执行一系列的指令了。
make 的核心概念是依赖关系和规则。它通过读取一个名为 Makefile 的文件来确定项目中各个文件之间的依赖关系,以及如何根据这些依赖关系执行相应的命令来生成目标文件。
依赖关系指的是某个目标文件(比如可执行文件或库文件)的生成依赖于其他的源文件或中间文件。例如,如果一个可执行文件依赖于多个 .c 源文件和 .h 头文件,make 会检查这些依赖文件的修改时间,如果依赖文件有更新,就会重新执行相应的编译命令来生成新的目标文件。

使用方法

我先在makefile中编写一段指令,然后跟着指令来学习。

mycode:mycode.cgcc mycode.c -o mycode
clean:rm -f mycode

请添加图片描述

我先创建了一个mycode.c文件,里面有一段C语言代码,然后生成的目标文件是mycode。在makefile文件中,发现了2段属性的代码,分别是gcc mycode.c -o mycode,该指令可以把源文件编译为可执行文件;rm -f mycode是删除mycode文件。编写完成之后,我们使用make工具就可以完成源代码的编译工作了。
请添加图片描述

C语言代码执行的结果是hello Linux,如果我再添加一段代码为printf("hello world\n");,不用像之前一样使用gcc mycode.c -o mycode这个指令,可以直接make后,再用./mycode就可以编译代码了,相比之前每次改变代码之后都需要执行gcc这条指令,让人感到很麻烦,所以make这个工具提高了我们的工作效率。
请添加图片描述

当我们执行完代码之后,想要删除mycode文件,只用使用make clean指令即可。
请添加图片描述


make原理

学会如何使用之后,我们来学习makefile文件中4条指令的作用都是什么。

mycode:mycode.cgcc mycode.c -o mycode
  • mycode:mycode.c:通过:把2个文件连接起来,叫做依赖关系。即 mycode 这个目标依赖于 mycode.c 文件。
  • gcc mycode.c -o mycode:这是依赖方法。它指定了使用 gcc 编译器将 mycode.c 编译成可执行文件 mycode依赖方法前必须使用Tab键隔开,不能使用4个空格。
    下面来看后2条指令
clean:rm -f mycode

该代码中,目标文件是clean,没有依赖文件列表,依赖关系是删除mycode指令,只用执行依赖方法中的代码。clean相当于vs中清理解决方案的操作。


现在我们有一个问题,

为什么执行mycode:mycode.c只需要make指令即可,而要删除mycode文件,则需要使用make clean指令呢?

根据上篇博客所学到的知识,我们把生成可执行目标文件分成4个过程。把这4个过程写进makefile文件当中。

mycode:mycode.ogcc mycode.o -o mycode
mycode.o:mycode.sgcc -c mycode.s -o mycode.o
mycode.s:mycode.igcc -S mycode.i -o mycode.s
mycode.i:mycode.cgcc -E mycode.c -o mycode.i
clean:rm -f mycode.i mycode.s mycode.o mycode

该文件是一个完整的C语言程序的编译链接过程,但是执行编译的过程中,应该依次生成.i,.s,.o三个文件,最后再生成可执行目标文件mycode。当进行第一条依赖关系的时候,就没有.o文件,第二个依赖关系缺少.s文件,依次类推,整个过程都是反过来的,那么还能成功执行makefile文件吗?
请添加图片描述

可以看出执行成功了。这是因为make会自动推导makefile中的依赖关系,就算把顺序颠倒了,也可以成功运行。
请添加图片描述

这个过程有点像递归过程,最开始只有mycode.c文件,只有找到了源文件,才能依次生成其它文件。
如果我们把clean指令放在最前面,再使用make指令会发生什么情况呢?
请添加图片描述

由图片可以看出,会先执行clean指令,原因是:当make后面不接任何目标时,make会从上往下找,找到第一个依赖关系并执行。不过建议还是把clean指令放在最后面。


接下来还有一个问题,

[!question]
如果源代码没有发生改动,为什么只能编译一次,多次编译后就无效了呢?这是如何做到的呢?

如图所示:
请添加图片描述

答案就是为了提高编译效率。代码没有发生改动的话,编译器只需要执行一次就可以了,因为多次编译之后结果还是一样的。试想一下,如果有一个工程文件,里面的代码有几百万行,编译一次的时间就需要几十分钟,如果其他人再来编译一次,又会浪费很长时间,所以只需要执行一次就行。
接着回答第2个小问:如何做到的
答:我们知道一定是源文件(.c)形成可执行文件(.exe)。先有源文件,才有可执行,一般而言,源文件的最近修改时间比可执行文件是要老的!如果我们更改了源文件,历史上曾经还有可执行文件,那么源文件的最近修改时间,一定要比可执行程序要新的。所以只需要比较,可执行程序的最近修改时间和源文件的最近修改时间:

.exe 新与 .c :源文件是老的,不需要重新编译
.exe 老与 .c :源文件是新的,需要重新编译

那么如何进行验证呢?我们需要用到一个新指令:stat 文件名这条指令可以查看文件的时间。
请添加图片描述

  • Access:访问时间。该文件最后一次被读取或执行的时间
  • Modify:修改时间(针对的是文件内容)
  • Change:更改时间(针对的是文件属性)
    在之前的学习中,我们知道==文件 = 文件内容 + 文件属性==。文件属性指的是文件的名称、大小、权限、存储位置等。
    请添加图片描述

由此可以得出结论:make会根据源文件和目标文件的新旧,判定是否需要重新执行依赖关系进行编译。如果想让对应的依赖关系总是被执行呢?那么就可以在makefile中添加.PHONY:文件名指令
请添加图片描述

不过不建议用.PHONY修饰可执行程序,一般用在清理工作当中。我们将它设置为伪目标,用 .PHONY 修饰,伪目标的特性是,总是被执行的。

.PHONY: clean
clean:rm -f mycode

makefile的特殊处理

mycode:mycode.cgcc -o $@ $^
.PHONY:clean
clean:rm -f mycode 

$@等价于冒号左边,$^等价于冒号右边
请添加图片描述

如果在依赖方法前面加个@符合,作用是不用显示gcc指令。

相关文章:

  • 求简单交错序列前N项和
  • 【Linux我做主】探秘gcc/g++和动静态库
  • RestControllerAdvice 和 ControllerAdvice 两个注解的区别与联系
  • 二十、FTP云盘
  • Operator 开发入门系列(一):Hello World
  • 【Java学习笔记】标识符和保留字
  • NLP高频面试题(四十七)——探讨Transformer中的注意力机制:MHA、MQA与GQA
  • 火山云如何运营
  • Vscode开发Vue项目NodeJs启动报错处理
  • 【Rust基础】crossbeam带来的阻塞问题
  • 大模型-mcp学习
  • 基于Django实现的图书分析大屏系统项目
  • 为什么要做种草商城
  • MAPLE:编码从自我为中心的视频中学习的灵巧机器人操作先验
  • LeetCode之两数之和
  • 驱动-原子操作
  • 《Java 泛型的作用与常见用法详解》
  • 【JavaScript】二十四、JS的执行机制事件循环 + location + navigator + history
  • 做Data+AI的长期主义者,加速全球化战略布局
  • 4月17日复盘
  • 范宇任上海宝山区副区长
  • 山西太原小区爆炸事故已造成17人受伤
  • 神十九乘组安全顺利出舱
  • 海量数据处于“原矿”状态,数据价值释放如何破局?
  • 辽宁省委书记、省长连夜赶赴辽阳市白塔区火灾事故现场,指导善后处置工作
  • 巴西外长维埃拉:国际形势日益复杂,金砖国家必须发挥核心作用