【Linux系统】自动化构建-make/Makefile的使用


一、make/Makefile 的简单介绍

make是一条命令(Linux系统内置),Makefile是一个文件(工程师自己创建),两个搭配使用,完成项目自动化构建。

  • 一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,Makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作
  • make是一个命令工具,是一个解释Makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,Makefile都成为了一种在工程方面的编译方法。
  • Makefile带来的好处就——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。

二、make/Makefile的基本使用

1.示例展现基本使用

要使用make指令,首先得创建一个Makefile文件,并在其中编辑一些操作:

[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 4
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ vim code.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ touch Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ vim Makefile

在这里插入图片描述

在这里插入图片描述
make指令能够执行Makefile文件中的操作:

[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 8
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
-rw-rw-r-- 1 zh zh 65 May 11 16:35 Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
gcc -o code code.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 20
-rwxrwxr-x 1 zh zh 8360 May 11 16:52 code
-rw-rw-r-- 1 zh zh   75 May 10 16:35 code.c
-rw-rw-r-- 1 zh zh   65 May 11 16:35 Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ./code
hello world
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make clean
rm -f code
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 8
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
-rw-rw-r-- 1 zh zh 65 May 11 16:35 Makefile

2.依赖关系和依赖方法

在这里插入图片描述

这个Makefile文件中,
依赖关系是 code:code.c。表示文件code,它依赖于code.c (而当前目录下存在code.c,可以执行依赖方法,不存在code.c会报错)

依赖方法是 gcc -o code code.c (实现依赖关系的方法)

make执行Makefile文件中的操作是自上而下的,所以直接使用make指令会默认执行Makefile文件中的第一个操作。
像clean这种,没有被第⼀个目标⽂件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示使用make执行,即命令——“make clean”,以此来清除所有的目标文件,以便重新编译。

3.伪目标(.PHONY 修饰)

⼀般这种clean操作,我们会将它设置为伪目标,用 .PHONY 修饰后就是伪目标,伪目标的特性是:总是被执行的。


  1. 要想理解伪目标总是被执行的特性,我们首先要感受一下不加 .PHONY 修饰的效果。这个Makefile文件中的第一个操作就是不加.PHONY 修饰,多次运行它展示一下效果:
    在这里插入图片描述
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 8
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
-rw-rw-r-- 1 zh zh 65 May 11 18:51 Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
gcc -o code code.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 20
-rwxrwxr-x 1 zh zh 8360 May 11 18:54 code
-rw-rw-r-- 1 zh zh   75 May 10 16:35 code.c
-rw-rw-r-- 1 zh zh   65 May 11 18:51 Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
make: `code' is up to date.
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
make: `code' is up to date.

只有第一次使用make指令时执行了Makefile文件中的第一个操作。

  1. 对比试验,将Makefile文件中的第一个操作设置为伪目标,再多次运行它展示一下效果:
    在这里插入图片描述
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 8
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
-rw-rw-r-- 1 zh zh 77 May 11 19:07 Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
gcc -o code code.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 20
-rwxrwxr-x 1 zh zh 8360 May 11 19:07 code
-rw-rw-r-- 1 zh zh   75 May 10 16:35 code.c
-rw-rw-r-- 1 zh zh   77 May 11 19:07 Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
gcc -o code code.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
gcc -o code code.c

发现每次使用make指令时都执行了Makefile文件中的第一个操作。通过对比试验确实能感受到伪目标总是被执行的特性


原理解析(解释Makefile文件中的第一个操作不加.PHONY 修饰时,为什么总是不被执行):
在这里插入图片描述
这实际上与文件的Modify时间有关。当第一次使用make指令时执行了Makefile文件中的第一个操作时,创建了code文件,code是后创建的,它的 Modify时间 是: 2025-05-11 19:35:10,比code.c文件的Modify时间新。
只有code.c文件的Modify时间比code文件的新时,后续使用make指令才会执行了Makefile文件中的第一个操作:

[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 8
-rw-rw-r-- 1 zh zh 102 May 11 19:26 code.c
-rw-rw-r-- 1 zh zh  65 May 11 19:25 Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
gcc -o code code.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 20
-rwxrwxr-x 1 zh zh 8360 May 11 19:35 code
-rw-rw-r-- 1 zh zh  102 May 11 19:26 code.c
-rw-rw-r-- 1 zh zh   65 May 11 19:25 Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
make: `code' is up to date.
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
make: `code' is up to date.
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ stat code.c
  File: ‘code.c’
  Size: 102       	Blocks: 8          IO Block: 4096   regular file
Device: fd01h/64769d	Inode: 927189      Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/      zh)   Gid: ( 1000/      zh)
Access: 2025-05-11 19:26:46.355112598 +0800
Modify: 2025-05-11 19:26:46.354112560 +0800
Change: 2025-05-11 19:26:46.354112560 +0800
 Birth: -
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ stat code
  File: ‘code’
  Size: 8360      	Blocks: 24         IO Block: 4096   regular file
Device: fd01h/64769d	Inode: 924027      Links: 1
Access: (0775/-rwxrwxr-x)  Uid: ( 1000/      zh)   Gid: ( 1000/      zh)
Access: 2025-05-11 19:35:10.459030471 +0800
Modify: 2025-05-11 19:35:10.459030471 +0800
Change: 2025-05-11 19:35:10.459030471 +0800
 Birth: -

我们修改一下 code.c 文件的Modify时间来验证一下上述结论,Modify时间是文件内容的最近修改时间,所以我们修改一下 code.c 文件中的内容就可以更新它的Modify时间。当更新了 code.c 文件的Modify时间后,使用make指令又能执行Makefile文件中的第一个操作,但只有更新之后第一次使用make命令有效,因为执行gcc -o code code.c 操作后,编译形成了新的 code 文件,它的Modify时间又比 code.c 文件的新了。

[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ vim code.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ stat code.c
  File: ‘code.c’
  Size: 75        	Blocks: 8          IO Block: 4096   regular file
Device: fd01h/64769d	Inode: 927189      Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/      zh)   Gid: ( 1000/      zh)
Access: 2025-05-11 19:44:53.539912417 +0800
Modify: 2025-05-11 19:44:53.538912380 +0800
Change: 2025-05-11 19:44:53.538912380 +0800
 Birth: -
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
gcc -o code code.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
make: `code' is up to date.
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
make: `code' is up to date.
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ stat code
  File: ‘code’
  Size: 8360      	Blocks: 24         IO Block: 4096   regular file
Device: fd01h/64769d	Inode: 924027      Links: 1
Access: (0775/-rwxrwxr-x)  Uid: ( 1000/      zh)   Gid: ( 1000/      zh)
Access: 2025-05-11 19:45:23.016018601 +0800
Modify: 2025-05-11 19:45:23.016018601 +0800
Change: 2025-05-11 19:45:23.016018601 +0800
 Birth: -

结论: Makefile文件中对于文件的编译操作不需要被设置为伪目标,因为当文件内容更改,Modify时间更新,文件才被重新编译,这样非常合理,能够使编译工作变得更加高效;
而clean等操作可以被设置成伪目标,因为清理等工作很重要,而且不像编译操作那么费时,每次使用时都应该被执行。

三、make自动推导依赖关系

在这里插入图片描述

[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 8
-rw-rw-r-- 1 zh zh  75 May 11 19:44 code.c
-rw-rw-r-- 1 zh zh 204 May 11 20:38 Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
gcc -E code.c -o code.i
gcc -S code.i -o code.s
gcc -c code.s -o code.o
gcc -o code code.o
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 48
-rwxrwxr-x 1 zh zh  8360 May 11 20:39 code
-rw-rw-r-- 1 zh zh    75 May 11 19:44 code.c
-rw-rw-r-- 1 zh zh 16872 May 11 20:39 code.i
-rw-rw-r-- 1 zh zh  1496 May 11 20:39 code.o
-rw-rw-r-- 1 zh zh   447 May 11 20:39 code.s
-rw-rw-r-- 1 zh zh   204 May 11 20:38 Makefile

在这里插入图片描述

make是如何工作的,在默认的方式下,也就是我们只输入make命令。那么:

  1. make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
  2. 如果找到,它会找文件中的第一个目标文件,在上面的例子中,他会找到 code 这个文件,并把这个文件作为最终的目标文件。
  3. 如果 code 文件不存在,或是 code 所依赖的后面的 code.o 文件的Modify时间要比 code 这个文件新,那么,他就会执行后面所定义的命令来生成 code 文件。
  4. 如果 code 所依赖的 code.o 文件不存在,那么 make 会在Makefile文件中继续向下找目标为 code.o 文件的依赖性,如果找到则再根据第3步的规则生成 code.o 文件。(如果code.o所依赖的 code.s 文件不存在,则进行与第4步同样的操作,这有点像一个堆栈的过程)
  5. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
  6. 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。

四、使用make/Makefile对多个.c文件进行自动化编译(语法补充)

1.定义变量

在这里插入图片描述

[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 8
-rw-rw-r-- 1 zh zh  75 May 11 19:44 code.c
-rw-rw-r-- 1 zh zh 259 May 11 22:54 Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
gcc   -c  code.c
gcc   -o  code  code.o 
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 24
-rwxrwxr-x 1 zh zh 8360 May 11 22:54 code
-rw-rw-r-- 1 zh zh   75 May 11 19:44 code.c
-rw-rw-r-- 1 zh zh 1496 May 11 22:54 code.o
-rw-rw-r-- 1 zh zh  259 May 11 22:54 Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ./code
hello world
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make clean
rm -f  code.o  code 
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 16
-rw-rw-r-- 1 zh zh   75 May 11 19:44 code.c
-rw-rw-r-- 1 zh zh  259 May 11 22:54 Makefile

对Makefile文件进行进一步改进,可以用 $@ 指代目标文件, $^ 指代依赖文件:

在这里插入图片描述

2.隐藏执行过程

在这里插入图片描述

在依赖方法前+@,当执行该条依赖方法时,会隐藏执行过程:

[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 8
-rw-rw-r-- 1 zh zh  79 May 11 23:10 code.c
-rw-rw-r-- 1 zh zh 338 May 11 23:08 Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 24
-rwxrwxr-x 1 zh zh 8360 May 11 23:10 code
-rw-rw-r-- 1 zh zh   79 May 11 23:10 code.c
-rw-rw-r-- 1 zh zh 1496 May 11 23:10 code.o
-rw-rw-r-- 1 zh zh  338 May 11 23:08 Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make clean
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 8
-rw-rw-r-- 1 zh zh  79 May 11 23:10 code.c
-rw-rw-r-- 1 zh zh 338 May 11 23:08 Makefile

3.模拟实现对多个.c文件的自动化编译

  1. 首先得先创建多个.c文件:
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 8
-rw-rw-r-- 1 zh zh  79 May 11 23:10 code.c
-rw-rw-r-- 1 zh zh 248 May 11 23:35 Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ touch code{1..5}.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 8
-rw-rw-r-- 1 zh zh   0 May 12 16:13 code1.c
-rw-rw-r-- 1 zh zh   0 May 12 16:13 code2.c
-rw-rw-r-- 1 zh zh   0 May 12 16:13 code3.c
-rw-rw-r-- 1 zh zh   0 May 12 16:13 code4.c
-rw-rw-r-- 1 zh zh   0 May 12 16:13 code5.c
-rw-rw-r-- 1 zh zh  79 May 11 23:10 code.c
-rw-rw-r-- 1 zh zh 248 May 11 23:35 Makefile
  1. 编辑Makefile文件:
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ vim Makefile

在这里插入图片描述
%.c 的作用是展开当前目录下所有的.c文件
%.o 的作用是展开所有.c文件的同名.o
$< 的作用是对展开的依赖.c文件,一个一个的交给gcc进行处理

  1. 使用make指令调用Makefile文件对多个.c文件进行自动化编译:
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ make
gcc   -c  code3.c
gcc   -c  code5.c
gcc   -c  code.c
gcc   -c  code4.c
gcc   -c  code1.c
gcc   -c  code2.c
gcc   -o  code code3.o code5.o code.o code4.o code1.o code2.o 
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ll
total 44
-rwxrwxr-x 1 zh zh 8520 May 12 16:20 code
-rw-rw-r-- 1 zh zh    0 May 12 16:13 code1.c
-rw-rw-r-- 1 zh zh  936 May 12 16:20 code1.o
-rw-rw-r-- 1 zh zh    0 May 12 16:13 code2.c
-rw-rw-r-- 1 zh zh  936 May 12 16:20 code2.o
-rw-rw-r-- 1 zh zh    0 May 12 16:13 code3.c
-rw-rw-r-- 1 zh zh  936 May 12 16:20 code3.o
-rw-rw-r-- 1 zh zh    0 May 12 16:13 code4.c
-rw-rw-r-- 1 zh zh  936 May 12 16:20 code4.o
-rw-rw-r-- 1 zh zh    0 May 12 16:13 code5.c
-rw-rw-r-- 1 zh zh  936 May 12 16:20 code5.o
-rw-rw-r-- 1 zh zh   79 May 11 23:10 code.c
-rw-rw-r-- 1 zh zh 1496 May 12 16:20 code.o
-rw-rw-r-- 1 zh zh  407 May 12 16:20 Makefile
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ./code
hello world!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值