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

makefile的基础规则与命名方式

Makefile的基础规则与命名方式

  • 1.Makefile的基础命名规则
  • 2.Makefile 之时间戳
  • 3.Makefile依赖执行顺序
  • 4.Makefile中的变量、[.PHONY]与[-]
    • 4.1 变量
    • 4.2 「-」的使用
    • 4.3 伪目标的使用

1.Makefile的基础命名规则

  编写 main.c 文件,在本次实验中将用简单的 hello world! 程序来验证 Makefile 的基本规则。

#include <stdio.h>

int main(void)
{
    printf("hello world!\n");
    return 0;
}

因为 Makefile 是为了自动管理编译、链接流程而存在的,因此 Makefile 的书写需要遵照一定的书写规则。

TARGET... : PREREQUISITES...
COMMAND
  • TARGET:规则目标,可以是一个 object file (目标文件),也可以是一个执行文件,还可以是一个标签(label)。
  • PREREQUISITES:要生成那个 target 所需要的文件或是目标,即规则依赖。
  • COMMAND:也就是 make 需要执行的命令,必须以 [TAB] 开始,由 shell 执行。

编写一个简单的 Makefile 文件用来管理 main.c 文件的编译。Makefile 文件的内容如下:

main: main.o
    gcc -o main main.o

main.o: main.c
    gcc -c main.c

make 工具的基本使用方法为:make TARGET

现在在 Terminal 输入命令:

make main.o

Terminal 的输出结果如图所示:
在这里插入图片描述
说明 shell 执行了命令 gcc -c main.c

接下来输入以下命令:

make main

执行生成的main文件,Terminal 中的输出结果如图所示:
在这里插入图片描述
说明程序得到了正确的执行。

在进行自动化编译之前,我们将生成的多余文件进行删除。

rm main.o main

由于我们的最终的目标是 main 文件,实际上我们并不关心中间目标文件 main.o。现在尝试只运行一次 make 编译出我们需要的最终目标。

make main

Terminal 的输出内容如图:
在这里插入图片描述
可以看出 make 还是先生成 makefile 中 main 的依赖文件 main.o,再链接生成 main 文件。让 make 自动寻找目标,即在 make 命令后不添加任何参数直接运行。首先删除之前产生的 main 和 main.o 文件。

rm main main.o

然后在 Terminal 中输入命令:

make

Terminal 的输出内容跟之前的输出内容相同:

这是因为默认情况下,make 会以第一条规则作为其终极目标。

现在我们尝试修改 makefile,在目标 main 之前再增加一条规则:

dft_test : middle_file
    mv middle_file dft_test
middle_file :
    touch middle_file

注意:在将这段代码复制到 WebIDE 中时需要观察一下此时 tab 的默认格式是 space:4 表示使用 4 个空格代替 制表符。

在这里插入图片描述
这样的话在执行 make 命令会出现以下错误:

在这里插入图片描述
解决办法是依次点击 Space:4->Indent Using Tabs->4 Configured Tab Size 然后删除 Command 那一行的缩进,重新使用 tab 缩进,保存之后重新执行 make 命令,问题将得以解决。

执行命令:

make

Terminal 输出结果如下:
在这里插入图片描述
说明规则得到了正确的执行,同时在当前文件夹下会产生一个新的文件 dft_test。

2.Makefile 之时间戳

make 命令在执行时会自动检测依赖文件的时间戳,具体规则如下:

  • 若依赖文件不存在或者依赖文件的时间戳比目标文件新,则执行依赖文件对应的命令。
  • 若依赖文件的时间戳比目标文件老,则忽略依赖文件对应的命令。

接下来对 makefile 时间戳规则进行验证,修改 makefile 文件内容:

#this is a makefile example

main:main.o testa testb
    gcc -o main main.o

main.o:main.c
    gcc -c main.c

testa:
    touch testa

testb:
    touch testb

清除可能存在的中间文件。
rm main.o testa testb
执行 make 命令。

make

Terminal 输出内容如下:
在这里插入图片描述
make 命令执行后分别生成 main.otestatestb 这三个中间文件。这验证了时间戳规则中的第一条。

现在删除 testb 文件,再观察 make 会如何执行。

make

Terminal 输出结果如图:
在这里插入图片描述

可见 make 分别执行了 testbmain 两条规则,main.otesta 规则对应的命令没有被执行。这验证了 makefile 时间戳规则中的第二条。

3.Makefile依赖执行顺序

make 目标文件的依赖文件是按照从左到右的顺序生成的。 它对应规则 main。

main:main.o testa testb
    gcc -o main main.o

make 按照顺序分别执行 main.o、testa、testb 所对应的规则。 现在我们调换 main.o、testa、testb 的顺序。 修改 makefile 文件的 main 规则的依赖顺序:

main: testb testa main.o

清除上次编译过程中产生的中间文件:

rm main.o testa testb

执行 make 命令。

make

Termianl 输出结果如图:
在这里插入图片描述

可见 make 的确是按照从左到右的规则分别执行依赖文件对应的命令。

4.Makefile中的变量、[.PHONY]与[-]

4.1 变量

  makefile 也可以使用变量,它类似于 C 语言中的宏定义。 变量可以直接使用「vari=string」的写法来定义,并以「$(vari)」格式来使用。 我们用变量来定义目标的依赖项,使 makefile 保持良好的扩展性。
在 makefile 中定义并使用变量,将 makefile 还原至以下内容:

#this is a makefile example

depen=main.o testa testb

main:main.o testa testb
    gcc -o main main.o

main.o:main.c
    gcc -c main.c

testa:
    touch testa

testb:
    touch testb

修改 main 的依赖声明。

main:$(depen)

执行 make 命令,并观察输出结果。
Terminal 输出结果如图:
在这里插入图片描述

可以看出 makefile 依然能够正常执行。 就算之后 main 目标的依赖项有变化时,也只需修改 depen 变量的值即可。

为 makefile 添加 clean 规则,因为每次测试 makefile 的时候我们都要清除中间文件,为了使得编译工程更加自动化,我们在 makefile 中添加规则让其自动清除。

在 makefile 中修改 depen 变量,增加 clean 依赖:

depen=clean main.o testa testb

增加 clean 规则及其命令。

clean:
    rm main.o testa testb

此时 makefile 的内容如下:

#this is a makefile example

depen=main.o testa testb clean

main:$(depen)
    gcc -o main main.o

main.o:main.c
    gcc -c main.c

testa:
    touch testa

testb:
    touch testb

clean:
    rm testa testb main.o

执行 make 命令并观察,执行结果。
在这里插入图片描述
说明现在 make 会先清除掉上次编译的中间文件并重建新的对应的文件。

在 clean 规则中也使用 depen 变量。

clean:
    rm $(depen)

然而当我们执行了 make 命令之后,发现问题产生了。
在这里插入图片描述
原来是因为 depen 变量指明 clean 为依赖项,因此执行 rm 命令时也会试图删除 clean 文件,这时就会出现错误。 而 make 在执行命令行过程中出现错误后会退出执行。

4.2 「-」的使用

  因为在大部分情况下我们不会将删除一个不存在文件时所产生的错误作为真正的错误来看待,为了让 rm 命令在执行过程中即使出现了错误,makefile 也能够继续执行不退出,我们需要用到「-」符号。 而「-」的作用是让 make 忽略该指令的错误。

现在修改 makefile 中的 clean 规则:

clean:
    -rm $(depen)

执行 make 命令并观察输出结果:
在这里插入图片描述
从输出结果来看,虽然 rm 指令报出错误,make 却依然可以生成 main 文件。

4.3 伪目标的使用

前面提到 makefile 依赖文件的时间戳若比目标文件旧,则对应规则的命令不会执行。 我们现在定义了一个 clean 规则,但如果文件夹下正好有一个 clean 文件会发生什么样的冲突呢? 我们先在当前目录下先新建一个 clean 文件:

touch clean

执行 make 命令,并观察输出结果。
在这里插入图片描述
发现 clean 规则没有的到执行,因为 clean 文件已经存在。然而 clean 实际上是一个伪目标,我们并不期望它会与真正 clean 文件有任何关联。 因此需要使用 .PHONY 来声明伪目标。

接下来修改 makefile 在变量 depen 之前加入一条伪目标声明。

.PHONY: clean

执行 make 命令并观察输出结果。
在这里插入图片描述
可以看到 makefile 又能得到正常执行了,并且所有流程都符合我们的预期。

现在删除掉 main 依赖项 testa 和 testb 因为在生成 main 文件过程中并不需要用到这两个文件。 修改 makefile 的 depen 变量:

depen=clean main.o

执行 make 命令并观察输出结果。
在这里插入图片描述

学到这里,我们就已经可以随心所欲的定制 main 的依赖规则了。

相关文章:

  • 自动驾驶仿真:角雷达坐标系转换详解
  • 教你如何制作浪漫的3D相册表白网站 HTML+CSS+JavaScript
  • 【Shell编程】Shell中for循环、while循环、until循环语句
  • Hadoop集群配置运行
  • 【数模/预测】灰色预测
  • 基于KDtree的电路故障检测算法的MATLAB仿真(包括matlab仿真录像)
  • 奇妙的“黑板擦”字符串
  • 神经网络参数的学习-损失函数与梯度下降
  • Go(Golang)编程语言
  • 简单DIV CSS布局网站 (HTML学生个人网站作业设计) 体育运动主题网页设计与实现
  • 知识点18--springboot多模块开发
  • 沉睡者IT:零基础学习短视频与+玩转抖音快手
  • 【CSS】伪类选择器有什么用?有哪些是常用的伪类?
  • VirtualBox虚拟机安装教程
  • docker 镜像打包发布
  • (三)从jvm层面了解线程的启动和停止
  • 【跃迁之路】【444天】程序员高效学习方法论探索系列(实验阶段201-2018.04.25)...
  • 2017届校招提前批面试回顾
  • axios 和 cookie 的那些事
  • LeetCode29.两数相除 JavaScript
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • PAT A1017 优先队列
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • Vue--数据传输
  • 闭包,sync使用细节
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 聊聊flink的BlobWriter
  • 配置 PM2 实现代码自动发布
  • 区块链分支循环
  • 手写双向链表LinkedList的几个常用功能
  • 数据科学 第 3 章 11 字符串处理
  • 为视图添加丝滑的水波纹
  • 正则表达式小结
  • Spring Batch JSON 支持
  • 阿里云API、SDK和CLI应用实践方案
  • ​secrets --- 生成管理密码的安全随机数​
  • # 数据结构
  • #pragma 指令
  • #我与Java虚拟机的故事#连载06:收获颇多的经典之作
  • (4)(4.6) Triducer
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (六)Hibernate的二级缓存
  • (七)微服务分布式云架构spring cloud - common-service 项目构建过程
  • (一)为什么要选择C++
  • (原創) 是否该学PetShop将Model和BLL分开? (.NET) (N-Tier) (PetShop) (OO)
  • .a文件和.so文件
  • .NET企业级应用架构设计系列之结尾篇
  • .sh
  • @RequestParam,@RequestBody和@PathVariable 区别
  • [AIGC] 开源流程引擎哪个好,如何选型?
  • [C++随笔录] 红黑树
  • [CF]Codeforces Round #551 (Div. 2)
  • [Codeforces] combinatorics (R1600) Part.2