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

Linux下的Makefile基本操作

1.Makefile与 make介绍

在Linux中, Makefile 是⼀个⽂件, 令会在当前⽬录下找 make 是⼀个指令,当使⽤ Makefile ⽂件从⽽执⾏内部的内容

2.创建第一个 Makefile并使用make

⾸先,在当前⽬录下创建⼀个makefile文件

接下来在同级⽬录下创建⼀个 code.c ⽂件

使⽤vim编辑器输⼊下⾯的内容:

 #include <stdio.h>int main(){printf("hello linux\n");return 0;}

保存c ode.c ⽂件后退出当前vim,使⽤vim打开 Makefile 文件 输⼊下⾯的内容:

code:code.cgcc -o code code.c.PHONY:cleanclean:rm -rf code

需要注意, gcc -o code code.c和 rm -rf code前⽅是⼀个Tab键的⼤ ⼩,⽽不是4个或者8个空格

保存M akefile ⽂件后退出当前vim,在当前⽬录下输⼊ make 指令即可在当前⽬录下 创建code.c 对应的可执⾏⽂件(具有可执⾏权限并且⽂件本身可执⾏) code ,例 如下图:

通过常规⽅式运⾏该可执⾏⽂件 ./code 即可看到打印输出的内容:

接着使⽤ make clean 指令清理刚才⽣成的可执⾏⽂件 code :

3.Makefile文件基本格式介绍

以前⾯例⼦中的 Makefile 为例:

 code:code.cgcc -o code code.c.PHONY:cleanclean:rm -rf code

第⼀⾏中的 code:code.c 代表依赖关系, code 表示⽬标⽂件, 赖⽂件列表中的⽂件,第⼆⾏的 code.c 表示依 gcc -o code code.c代表依赖⽅法(指令)

第三⾏中的 .PHONY 表示⽣成⼀个伪⽬标, clean 表示伪⽬标的名字(可以类⽐ 变量名)

第四⾏及第五⾏与第⼀⾏及第⼆⾏含义⼀致,表示依赖关系和依赖⽅法,⽽因为 clean 没有需要依赖的⽂件,所以 clean: 后没有任何依赖⽂件列表⽂件

依赖关系:表示两个⽂件之间构成的⼀定关系,⽐如⽗⼦关系

依赖⽅法:通过依赖⽅法可以执⾏的对应的指令

依赖⽂件列表: code.c 所处的位置即为依赖⽂件列表,为了⽣成⽬标⽂件 code 而需要的⽂件称为依赖⽂件,依赖⽂件列表可以含有不⽌⼀个⽂件

注意:理论上来说,依赖⽂件列表中的  code.c 在当前情况下可以不写,但是如 果不写,在第⼀次执⾏ make 指令后,不论之后 code.c 是否修改,再执⾏ make 指令都⽆法执⾏对应的依赖⽅法,因为 code ⽂件已经存在,所以为了保 证可以修改,需要加上 code.c

从上⾯的运⾏结果可以看出,每⼀次执⾏make时都会在控制台回显出对应的依赖⽅ 法,如果将编译指令改为 echo "测试",则效果如下:

可以看到先回显了对应的依赖⽅法,再执⾏依赖⽅法,如果不希望出现这种情况,可 以在执⾏的指令前加上@使指令不再回显,所以上⾯的 Makefile 可以修改为:

 code:code.c2   @echo "Start Compiling..."3   @gcc -o code code.c4   @echo "End Comliling"5 .PHONY:clean6 clean:7     @echo "Cleaning code..."8     @rm -rf code9     @echo  "End Cleaning..."10                                                                                   
~

⼀个依赖集中可以有多个依赖⽅法

此时正常运⾏结果如下:

如果代码出现错误,则 gcc 会中断编译,所以此时运⾏结果如下:

使⽤. PHONY 可以⽣成⼀个指定名字的伪⽬标,伪⽬标的作⽤是:清除依赖⽅法执⾏ 时进⾏的⽂件时间对⽐,下⾯是具体介绍: ⾸先,在Linux中可以使⽤ stat+⽂件名查看⽂件当前的属性,对于 code.c 有:

执⾏结果中,主要关注三个部分: Access 、 Modify 和 Change ,这三个部分分别 表示⽂件最近⼀次的访问时间、⽂件内容被修改的时间和⽂件属性被修改的时间

Access 时间:⼀般不是特别精确,因为如果⼀个⽂件访问⼀次就需要更新⼀次 访问时间,那么对于多个⽂件来说,这种操作的消耗对于CPU来说是很⼤的

Modify 时间: Modify 时间只表示⽂件内容被修改的时间,如果⽂件属性时间 修改,则不影响 Modify 时间,但是需要注意, 着Ch Modify 时间⼀旦改变⼀般伴随 ange 时间改变,因为修改⽂件内容有时会影响到⽂件的相关属性(例如⽂ 件⼤⼩等)

Change 时间:Change 时间只表示⽂件属性被修改的时间,修改⽂件属性时间不会影响Modify时间

接着,观察对于没有添加伪⽬标的 Makefile 第⼀部分依赖集,如果code文件已经存在,再一次进行make的效果:

code:code.c@echo "Start Compiling..."@gcc -o code code.c@echo "End Compiling..."

那么指令是如何知道⽂件是否被修改呢?就是通过前⾯提到的 Modify 时间和 Change 时间,过程如下图所示:

因为code.c 创建的时间早于 code.c 编译的时间,所以开始时不存在 所以第⼀次执⾏ code ⽂件, make 指令时正常执⾏。

当code.c ⽂件未修改时,第⼆次执⾏ make 指令会发现 code.c 的 Change 时间依旧在 make 之前,因为第⼀次已经满⾜了 Modify 时间和 code.c 的两个时间在 code ⽂件的两个时间之前,所以 gcc 就不会再进⾏⼀次编译。

当修改 code.c ⽂件后, code.c 的 的两个时间在 Modify 时间和 Change 时间改变,导致 code ⽂件的两个时间之后,此时 code.c gcc 就可以正常执⾏,从⽽ make 指 令不受影响

⽽如果再 Makefile 中为这⼀部分添加⼀个伪⽬标,则可以清除指令中⽂件时间的对 ⽐过程:

.PHONY:codecode:code.c@echo "Start Compiling..."@gcc -o code code.c@echo "End Compiling..."

此时⽆论执⾏多少次 make 指令,都不会出现 : make 指令中 gcc 因为⽂件时间对⽐⽽导致执⾏结果不同

make 指令虽然结果完全相同,但是不代表依赖⽅法没有执⾏,即⽂件确实每⼀ 次都重新编译

执⾏完编译部分的 make 指令,想要执⾏删除 code ⽂件对应的 make 后加上 clean ,这个 make 指令需要在 clean 代表伪⽬标名,之所以前⾯直接使⽤ make 就可以 执⾏编译指令,是因为 make 指令在读取 Makefile ⽂件时是从上⾄下顺序查找,⽽ 直接使⽤ make ,就会执⾏第⼀个依赖集对应的依赖⽅法,执⾏完毕后就不会再继续 往下读;⽽对于删除 code ⽂件的指令来说,其所在位置时Makefile 中的第⼆个依赖集,所以需要告诉 make 指令找哪⼀部分

所以,此处可以看出.PHONY 的第⼆个作⽤就是声明⼀个伪⽬标,通过该伪⽬标帮助make 指令快速定位需要执⾏的依赖集

如果细⼼可以发现,对于 clean 依赖集来说,不论是否有 .PHONY 都可以⽆限制执⾏ rm -rf依赖⽅法,所以可以推断出 rm -rf指令本身不会考虑⽂件的时间属性,但 是为什么此处还需要加 .PHONY ?⼀⽅⾯是为了声明伪⽬标,另⼀⽅⾯是为了当前依 赖集中的其他指令会有时间对⽐

4.Makefile通用写法

在前⾯的Makefile中,每⼀个依赖⽅法都需要在前⾯的依赖关系部分的⽂件重新写⼀ 遍,为了简化过程,可以使⽤下⾯的写法:

 TARGET=codeSRC=code.o$(TARGET):$(SRC)$(CC) -o $@ $<%.o:%.c$(CC) -c $< -o $@.PHONY:cleanclean:@rm -rf $(TARGET) $(SRC)

上⾯的代码中,⾸先创建了两个变量分别代表⽣成的⽬标⽂件 code 以及第⼀个依赖 集中的依赖⽂件列表中的⽂件,在依赖⽅法中使⽤了两个⾃动变量(⼀般建议⼤ 写),分别是$@和$<

在M akefile 中, $@ 表示⽣成的⽬标⽂件,$<表示从依赖⽂件列表中取出⼀个⽂ 件,对应的还有$^表示依赖⽂件列表中的所有⽂件

⽽对于gcc来说,在 Makefile 中可以使⽤内置变量 如果涉及到多个⽂件编译,则在 SRC 和 CC (表示C编译器的名字)代替 %.c 处使⽤空格分隔每⼀个⽂件

⾄此,⼀个基本的 Makefile ⽂件编写语法就这么多


http://www.mrgr.cn/news/48127.html

相关文章:

  • 重温设计模式--职责链模式
  • information_schema是什么?
  • sentinel学习笔记7-熔断降级
  • 计算机网络压缩版
  • 0基础学前端-----CSS DAY5
  • 【落羽的落羽 C语言篇】自定义类型——结构体
  • Redis 的安装与部署(图文)
  • 中间件:SpringBoot集成Redis
  • FLBOOK一款强大的电子产品图册制作工具
  • springboot健康管理平台-计算机毕业设计源码38430
  • 【unity框架开发9】序列化字典,场景,vector,color,Quaternion
  • 孤独相伴 - 结婚十七年
  • 从数据到洞察:ChatGPT如何革新Python数据分析流程
  • 跟着深度学习好书实践tensorflow神经网络
  • NRF24L01原子HAl库学习
  • cuda实现gemm
  • numpy学习
  • 上门服务系统|上门服务小程序|上门服务系统成品
  • 2024系统分析师---试题四:论数据分片技术及其应用
  • 如何找到I2c设备的地址以及读写寄存器
  • AI核身-金融场景凭证篡改检测Baseline实践
  • 1 线性系统性能分析方法1——时域分析法
  • AI-MO x Numina | 工具集成的数学推理
  • gradle build --offline idea怎么配置 打包命令使用gradle build --offline进行打包怎么操作
  • Redis的基础篇
  • makefile与gdb的使用