认识Makefile文件(什么作用,格式怎样,如何工作)

以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。

参考博客:Make 命令教程 - 阮一峰的网络日志

一、Makefile文件是什么

Makefile 文件描述了 Linux 系统下 C/C++ 工程文件的编译规则,比如某些文件是否需要编译、文件编译的顺序、文件间的依赖关系、文件是否需要重建等等。

它用来自动化编译 C/C++ 项目。一旦写编写好 Makefile 文件,只需要一个 make 命令,整个工程就开始自动编译,不再需要手动输入一堆源文件与参数,也不需要手动执行 GCC 命令。

以 Linux 下的C语言开发为例。多文件编译生成一个文件,编译的命令如下所示:

gcc -o outfile name1.c name2.c ...

outfile 是要生成的可执行程序的名字,nameN.c 是源文件的名字。当源文件的数量不多时,可以选择这样的编译方式,但如果源文件很多,会遇到下面问题。

(1)编译的时候需要链接库的的问题

拿C语言来说,编译的时候 gcc 只会默认链接一些基本的C语言标准库,很多源文件依赖的标准库都需要我们手动链接。比如,下面列举了一些需要我们手动链接的标准库:

  • name1.c 用到了数学计算库 math 中的函数,我们得手动添加参数 -Im;
  • name4.c 用到了小型数据库 SQLite 中的函数,我们得手动添加参数 -lsqlite3;
  • name5.c 使用到了线程,我们需要去手动添加参数 -lpthread。

除了标准库,还有其他文件需要链接第三方库。这导致编译命令非常长,而且可能会涉及到文件链接的顺序问题,所以手动编译会很麻烦。如果使用 Makefile 就不一样了,它会彻底简化编译的操作。把要链接的库文件放在 Makefile 中,制定相应的规则和对应的链接顺序。这样只需要执行 make 命令,工程就会自动编译。每次想要编译工程的时候就执行 make ,省略掉手动编译中的参数选项和命令,非常方便。

(2)编译大的工程会花费很长的时间

如果我们去做项目开发,免不了要去修改工程项目的源文件,每次修改后都要去重新编译。一个大的工程项目可不止有几个的源文件,里面的源文件个数可能有成百上千个,比如一个内核或者是一个软件的源码包。要完巨量文件的编译,消耗的时间很长。

Makefile 支持多线程并发操作,会极大的缩短我们的编译时间。而且编译整个工程的时候,make 命令只会编译我们修改过的文件,没有修改的文件不用重新编译,这也缩短了编译时间。

当然还可能遇到其他问题,比如:工程文件中的源文件的类型很多,需要选择不同的编译器;文件可能会分布在不同的目录中,使用时需要调整路径等等。这些问题都可以通过Makefile 来解决。

我们只需要完整地编写一次Makefile文件,以后只要不增加或者是删除工程中的文件,Makefile 基本上不用去修改。

Makefile这些特征为为我们提供了极大的便利,很大程度上提高编译的效率。

二、Makefile文件的书写规则

1、规则的格式说明

(1)Makefile 描述的是文件编译的相关规则,它的规则主要是两个部分组成:依赖的关系(目标与依赖)、执行的命令。其结构如下所示:

targets : prerequisites
    command
#或者
targets : prerequisites; command
    command
  • targets是规则的目标。可以是 Object File(一般称它为中间文件),也可以是可执行文件,还可以是一个标签。
  • prerequisites是依赖文件,是生成 targets 所需要的文件或者是目标。可以多个,也可以没有。
  • command是make时执行的命令(任意的 shell 命令)。一条规则中可以有很多行的命令;每行命令可以有很多条命令,每行中的多条命令之间用分号隔开;每行命令后面不需要添加什么符号表示结束。
  • 目标和依赖文件之间要使用冒号分隔开,命令的开始一定要使用Tab键。

(2)下面代码实现的功能就是编译 test.c 文件。其中 test 是目标文件, test.c 是依赖文件,重建目标文件需要执行的命令是gcc -o test test.c。然后我们在 shell 中执行 make 命令,程序就会自动执行,得到最终的目标文件。这就是 Makefile 的基本语法与使用方法。

test:test.c
    gcc -o test test.c

2、Makefile的内容

一个完整的Makefile文件中包含以下内容:规则、变量的定义、文件指示、注释等内容。

(1)规则。规则包括显式规则、隐晦规则。显式规则说明如何生成一个或多的的目标文件,由 Makefile 的书写者明显指出要生成的文件、依赖文件和生成命令。隐晦规则是指由于 make 命令有自动推导的功能,我们可以简略地书写 Makefile。

(2)变量的定义。在 Makefile 中定义的变量一般都是字符串,当 Makefile 被执行时,其中的变量都会被扩展到相应的引用位置上。

(3)文件指示。文件指示包括三个部分,一个是在一个 Makefile 中引用另一个 Makefile,就像C语言中的 include 一样;另一个是根据某些情况指定 Makefile 中的有效部分,就像C语言中的预编译 #if 一样;还有就是定义一个多行的命令。

(4)注释。Makefile 中只有行注释,和 UNIX 的 Shell 脚本一样,其注释是用“#”字符。如果要在Makefile中使用“#”字符,可以用反斜杠进行转义,如“\#”。

三、Makefile的工作流程

当执行 make 命令时,make 就会到当前文件下寻找将要执行的编译规则,即 Makefile 文件。

Makefile文件的文件名可以是GNUmakefile、makefile 和 Makefile,一般写成Makefile。

make命令也是按照这个顺序去寻找Makefile文件。如果文件不存在,则make 就会给我们报错。

make:*** 没有明确目标并且找不到 makefile。停止

1、Makefile 的具体工作流程

通过例子来说明Makefile 的具体工作流程。Makefile文件内容如下:

main:main.o test1.o test2.o
    gcc main.o test1.o test2.o -o main
main.o:main.c test.h
    gcc -c main.c -o main.o
test1.o:test1.c test.h
    gcc -c test1.c -o test1.o
test2.o:test2.c test.h
    gcc -c test2.c -o test2.o

在 shell 中执行 make 命令时,make 执行的是 Makefile 文件中的第一个规则即Makefile 文件中从上到下第一次出现依赖关系的那个规则,此规则的目标称之为“终极目标”。

在上述例子中,第一个规则就是目标 "main" 所在的规则。该规则描述了 目标"main" 的依赖关系,并定义了链接 ".o" 文件以生成目标 "main" 的命令。在执行这个规则所定义的命令之前,首先处理目标 "main" 的依赖文件(即main.o、test1.o、test2.o这些文件)的更新规则。

对这些 ".o" 文件为目标的规则处理有下列三种情况:

(1)目标 ".o" 文件不存在,则使用其描述规则创建它。

(2)目标 ".o" 文件存在,但是它所依赖的 ".c" 文件和 ".h" 文件中的任何一个文件比它更(第四声)新(在上一次 make 之后被修改),则根据规则重新编译生成它。

(3)目标 ".o" 文件存在,目标 ".o" 文件比它的任何一个依赖文件更新(它的依赖文件在上一次 make 之后没有被修改),则什么也不做。

通过上面的更新规则,我们可以了解到中间文件(即编译时生成的 ".o" 文件)的作用,即检查某个源文件是否进行过修改,判断最终目标文件是否需要重建。我们执行 make 命令时,只有那些修改过的源文件或者是不存在的目标文件才会进行重建,而那些没有改变的文件不用重新编译,这样在很大程度上节省时间,提高编程效率。

2、清除工作目录中的过程文件

中间文件会让整个工程看起来很乱,因此在编写 Makefile 文件时,一般会在末尾加上下面这样的规则语句,来清理编译时的中间文件和生成的最终目标文件,方便我们下次的使用。

.PHONY:clean
clean:
    rm -rf *.o test

PHONY中文意思是“虚假”,因此“.PHONY”表明clean是一个伪目标。clean不是具体的文件,不会与第一个目标文件产生任何关联,因此执行 make 时不会执行它下面的命令。

以前不了解Makefile时存在的疑惑:Makefile文件中那么多的目标,想要达成这些目标,在make的时候,是在后面一个个地添加目标吗?还是说只要make第一个目标,就会顺序地带动其他目标?现在看来,默认情况下执行的是第一个目标,其他目标如果是第一个目标的依赖文件,则会先处理其他目标,处理完之后才进行第一个目标的命令执行。当然,我们也可以在make后面直接指定目标,比如这里的make clean。

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天糊土

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值