前言
本文只讲LInux环境下的Makefile基础语法,环境搭建见下链接:
https://blog.youkuaiyun.com/weixin_44567668/article/details/125189852
一、概述
学过C语言都知道需要编译才能运行,其实运行的是可执行文件,可能是.obj或者.o文件,而将源文件.c变成可执行文件的过程就是编译,实际上GCC整个编译流程是:预处理、编译、汇编和链接,如使用下面命令进行编译:
gcc main.c -o main
那有人好奇Makefile有什么用?上面知道计算机系统运行需要一个可执行文件,我们只有一个main.c文件只需要一个命令,但是如果有很多个源文件和头文件的时候一个个敲命令,特别是在修改了其中某个文件后,一行行敲命令很显然不现实。而Makefile可以有效的解决这个问题,Makefile本质上相当于一个shell脚本文件,那样你将所有编译命令集中在一起,最后只需要输入make
命令就可以自动化编译,make与Makefile关系如下图:
这就是 make 的执行过程,make 工具就是在 Makefile 中一层一层的查找依赖关系,并执行相应的命令运行gcc编译器,编译出最终的可执行文件
二、示例引用
首先新建一个main.c的源文件,内容如下:
#include "stdio.h"
int main()
{
printf("hello, world! This is a C program.\n");
return 0;
}
然后新建名为Makefile的文件,内容如下:
main:main.o
gcc -o main main.o
main.o:main.c
gcc -c main.c
clean:
rm *.o
rm main
先不管语法后面会讲,然后在命令行里输入make
命令即可执行Makefile,注意main.c、Makefile与终端当前路径是一致的,然后输入./main
运行代码看效果
可以看出就3步:编辑工程代码->编辑Makefile文件->输入make执行编译
三、Makefile规则与运行
3.1 书写格式
- Makefile的语法规则
[目标]:[依赖]
[命令]
由上一小节的例子可以看出就是目标文件指向对应的依赖文件,然后下面就是具体的转换命令。注意:Makefile文件命令行的首行缩进用Tab键,不能使用空格
-
通配符
make支持3种通配符:*
、?
和[]
。通配符代替了一系列文件,如“ *.c ”代表后缀为.c的文件 -
模式规则
模式规则中,至少在规则的目标定定义中要包涵%
,否则就是一般规则,目标中的“%”表示对文件名的匹配,“%”表示长度任意的非空字符串,比如“%.c”就是所有的以.c 结尾的文件,类似与通配符:
%.o : %.c
命令
- 注释
在Makefile里使用#
添加注释,可以用反斜框进行转义,如\#
3.2 命令格式
- 显示命令
- 通常,make会把其要执行的命令行在命令执行前输出到屏幕上。当我们用
@
字符在命令行前,那么,这个命令将不被make显示出来 - 如果make执行时,带入make参数
-n
或--just-print
,那么其只是显示命令,但不会执行命令,这个功能很有利于我们调试我们的 Makefile - 而make参数
-s
或--slient
则是全面禁止命令的显示
- 命令执行
当依赖目标新于目标时,也就是当规则的目标需要被更新时,make 会一条一条的执行其后的命令。需要注意的是,如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号;
分隔这两条命令,如:
exec:
cd /home/hchen;pwd
- 命令出错
有些时候,命令的出错并不表示就是错误的。为了做到这一点,忽略命令的出错,我们可以在 Makefile 的命令行前加一个减号-
clean:
-rm -f *.o
还有一个全局的办法是,给 make 加上-i
或是--ignore-errors
参数,那么,Makefile 中所有命令都会忽略错误。而如果一个规则是以.IGNORE
作为目标的,那么这个规则中的所有命令将会忽略错误。
还有一个要提一下的 make 的参数的是-k
或是--keep-going
,这个参数的意思是,如果某规则中的命令出错了,那么就终目该规则的执行,但继续执行其它规则
- 定义命令包
如果 Makefile 中出现一些相同命令序列,那么我们可以为这些相同的命令序列定义一个变量。定义这种命令序列的语法以define
开始,以endef
结束,如:
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef
这里,“run-yacc”是这个命令包的名字,其不要和 Makefile 中的变量重名。调用示例如下:
foo.c : foo.y
$(run-yacc)
3.3 make的运行
-
make的工作方式
①读入所有的 Makefile。
②读入被 include 的其它 Makefile。
③初始化文件中的变量。
④推导隐晦规则,并分析所有规则。
⑤为所有的目标文件创建依赖关系链。
⑥根据依赖关系,决定哪些目标要重新生成。
⑦执行生成命令。 -
Makefile的文件名
默认的情