☰
(Linux)make的使用与Makefile文件的编写
2026/10/16 1:43:00 网站建设 项目流程

make与Makefile的简介

名字叫Makefile的文件就是Makefile文件,M也可以是小写。make是一个命令,用于生成文件。二者用于大型项目中快速处理文件。我们从基础部分开始,make的使用格式是

make [目标文件]

要生成文件,肯定要给出生成该文件的方法,生成方法要写在Makefile文件中。使用make命令就要在当前的路径下创建并编写Makefile文件,make命令会根据Makefile文件中的内容生成目标文件。

Makefile文件的编写

基本写法

首先是给出依赖关系,必须顶格写,指出生成目标文件需要用到哪些文件,格式是

[目标文件]:[依赖文件列表]

这些需要用到的文件就是依赖文件,比如要生成目标文件code需要使用code.c文件,code.c就是依赖文件,依赖文件列表可以没有任何依赖文件,可以只有一个依赖文件,也可以有多个依赖文件,两两用空格隔开即可。目标文件也可以有多个,不过意义不大,make其中一个会仍然会执行所有的依赖方法。

接着写依赖方法,必须以Tab键开头。使用依赖文件生成目标文件的方法就叫依赖方法,例如我们通过命令gcc code.c -o code使用code.c生成code文件就是一种依赖方法。

编写完成之后执行make命令就会根据Makefile中目标文件的依赖方法生成文件。如果没有指明要生成的目标文件,则从上往下扫描Makefile中的内容并生成第一个扫描到的目标文件。例如下面这个Makefile文件,直接使用make会生成code文件

伪目标

make也可以不生成文件只执行命令,仍然是在Makefile文件里面定义目标的依赖关系和依赖方法,这种只进行某些操作而不生成文件的目标被称为伪目标。比如我们可以加一个用于快速清理文件的目标clean,如下

这种写法有很大的问题,如果当前路径下刚好有个文件叫clean,此时我们输入命令make clean并不会删除文件,因为执行make命令会比较依赖文件和目标文件的更改时间(Modify时间),如果目标文件更改时间晚于依赖文件,说明依赖文件没有改过,因此为了不浪费资源没有生成新的目标文件。这里由于目标文件clean没有依赖文件,当前路径下的clean文件被认为是最新的,于是没有生成伪目标clean,也就没有执行对应的依赖方法了。

为此,我们可以用.PHONY修饰目标clean,.PHONY 是使得对应的依赖方法总是被执行,不会因为文件新旧等原因不执行。只要make clean,就一定会执行删除操作。但是诸如前面的temp、test等等有生成文件的目标不建议用.PHONY修饰,因为在大型项目中,生成一个目标文件可能需要很久,如果总是执行会浪费大量的时间和资源。

.PHONY:clean clean: rm code test temp

依赖链

有时目标文件并不能用依赖对象一步到位地生成,中间需要生成一些过渡文件,我们就从最终文件开始编写各个文件直接的依赖关系和依赖方法,如下:

​​​​​​​原过程

Makefile

make code 命令执行结果:

执行make命令会从上到下扫描Makefile文件,当遇到依赖文件不存在时,会先将依赖方法存到一个栈中,直到找到已经存在的依赖文件或者可以执行的依赖方法。

变量与赋值

Makefile文件中也可以实现类似定义变量并赋值的操作,赋值符号有很多,我们暂且使用比较好记的 = ,赋值后用 $(变量名) 使用。如下,其中echo指令相当于一个输出函数,可以输出后面的内容,(Linux下字符串仍然是用双引号)。

上面的结果中echo命令本身也显示出来了,如果只想保留命令执行结果,不看命令本身,可以在Makefile中对应的命令前加上符号 @。除了用目标文件赋值,依赖文件、指令、选项甚至是命令的结果都可以拿来赋值。 如gcc code.c -c code 这四个部分都可以赋值给变量。

基础特殊符号与大量文件处理

学会编写简洁的Makefile文件是快速处理大量文件的前提,这需要掌握一些特殊符号的使用技巧。例如我们要用code1.c、code2.c、code3.c生成可执行文件code。用到的所有命令如下

分为两个部分,一是逐个生成对应的.o文件,二是生成可执行文件。对于第一部分,一个一个写依赖关系和依赖方法比较繁琐。我们先使用%编写依赖关系如下

%.o : %.c

% 是类似命令中的 * 一样的通配符,在上面这个依赖关系中,%.c指的是所有带.c后缀的文件(注意make命令只会在当前路径下查找依赖文件),%.o类似。这样一来,当我们使用命令make [.o文件的文件名] 时,make命令就会将同名的.c 文件作为依赖文件。

由于依赖关系中没有说明具体的文件名是什么,依赖方法中也要用特殊符号来指代依赖文件,如下。

@ gcc -c $< -o $@

其中$@表示目标文件,$<表示依赖文件列表中的第一个依赖文件,也可以使用$^来表示所有的依赖文件,即依赖文件列表。完成之后就可以用make将所有的.c文件分别生成同名.o文件

Makefile内容:

make执行结果:

(这里仍然是一个一个生成,看起来依旧很繁琐,不过等我们编写完成之后就能实现一步到位)

接着是第二部分, .o文件的链接。我们不难发现要链接.o文件时需要把所有的.o文件一起转换成目标文件,如果文件很多,直接写的话依赖关系和依赖方法都很长。前面的%.o虽然能指代所有的.o文件,但是只能用于分别生成目标文件,我们这里需要将所有的.o文件用一条命令链接起来。

办法还是有的。首先,这些要链接起来的.o文件是后来生成的,一开始只有.c文件,但是二者是同名的。我们将.c文件的文件名一起赋值给一个变量,然后将后缀都改成.o再赋值给另一个变量。makefile中可以执行命令并将命令的执行结果赋值给变量,如下面这行语句的意思就是将命令 ls *.c 的结果赋值给allc

allc=$(shell ls *.c)

shell后面接命令就是执行这个命令的意思,不过要加上$(),否则会被认为是变量或者文件。下面的语句可以将ls *.c的结果(当前路径下所有的.c文件名)赋值给all,再将allc中每个文件名的.c后缀改成.o赋值给allo

allo=$(allc:.c =.o)

注意不要插上空格,否则可能会失效。完成后就能轻松地写依赖关系和依赖方法了

编写好之后,我们直接执行make code命令,由于.o文件不存在,会根据前面写的依赖关系(即 %.o : %.c)和依赖方法生成.o文件,再用生成的.o文件生成目标文件code。如此一来,我们就实现了使用一次make命令处理多个文件。

最后加上清理文件用的伪目标clean,一个简洁高效的Makefiel文件就编写完成了。

附录

Makefile文件内容

code.h文件内容

code1.c文件内容

code2.c文件内容

code3.c文件内容

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询