【Linux】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文件 输⼊下⾯的内容:

cpp 复制代码
code:code.c
 gcc -o code code.c
 .PHONY:clean
 clean:
 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 为例:

cpp 复制代码
 code:code.c
 gcc -o code code.c
 .PHONY:clean
 clean:
 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 可以修改为:

cpp 复制代码
 code:code.c
  2   @echo "Start Compiling..."
  3   @gcc -o code code.c
  4   @echo "End Comliling"
  5 .PHONY:clean
  6 clean:
  7     @echo "Cleaning code..."
  8     @rm -rf code
  9     @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的效果:

cpp 复制代码
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 中为这⼀部分添加⼀个伪⽬标,则可以清除指令中⽂件时间的对 ⽐过程:

cpp 复制代码
.PHONY:code
     code: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中,每⼀个依赖⽅法都需要在前⾯的依赖关系部分的⽂件重新写⼀ 遍,为了简化过程,可以使⽤下⾯的写法:

cpp 复制代码
 TARGET=code
 SRC=code.o
 $(TARGET):$(SRC)
 $(CC) -o $@ $<
 %.o:%.c
 $(CC) -c $< -o $@
 .PHONY:clean
 clean:
 @rm -rf $(TARGET) $(SRC)

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

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

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

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

相关推荐
吃肉不能购38 分钟前
Label-studio-ml-backend 和YOLOV8 YOLO11自动化标注,目标检测,实例分割,图像分类,关键点估计,视频跟踪
运维·yolo·自动化
学Linux的语莫42 分钟前
Ansible使用简介和基础使用
linux·运维·服务器·nginx·云计算·ansible
qq_312920111 小时前
docker 部署 kvm 图形化管理工具 WebVirtMgr
运维·docker·容器
踏雪Vernon1 小时前
[OpenHarmony5.0][Docker][环境]OpenHarmony5.0 Docker编译环境镜像下载以及使用方式
linux·docker·容器·harmonyos
Onlooker1291 小时前
云服务器部署WebSocket项目
服务器
学Linux的语莫1 小时前
搭建服务器VPN,Linux客户端连接WireGuard,Windows客户端连接WireGuard
linux·运维·服务器
legend_jz1 小时前
【Linux】线程控制
linux·服务器·开发语言·c++·笔记·学习·学习方法
Komorebi.py1 小时前
【Linux】-学习笔记04
linux·笔记·学习
黑牛先生1 小时前
【Linux】进程-PCB
linux·运维·服务器
Karoku0661 小时前
【企业级分布式系统】ELK优化
运维·服务器·数据库·elk·elasticsearch