http://c.biancheng.net/makefile/
1.简介
- makefile的作用是在工程化开发中对工程项目定义编译规则。使用make命令,整个工程就会自动编译。make命令是一个命令工具,是一个解释makefile中指令的命令工具。
- makefile文件主要包含的五个主要部分
- 显式规则
显式规则说明了,如何生成一个或多个目标文件。这是由 Makefile 的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。 - 隐晦规则
由于我们的 make 命名有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写 Makefile,这是由 make 命令所支持的。 - 变量的定义
在 Makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点像C语言中的宏,当 Makefile 被执行时,其中的变量都会被扩展到相应的引用位置上。 - 文件指示
其包括了三个部分,一个是在一个 Makefile 中引用另一个 Makefile,就像C语言中的 include 一样;另一个是指根据某些情况指定 Makefile 中的有效部分,就像C语言中的预编译 #if 一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。 - 注释:Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像 C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“#”。
- 显式规则
2.Makefile中的通配符
- *:匹配零个或者任意多个字符
- ?:匹配任意一个字符
- []:可以将指定匹配的字符放在[]中
test:*.c
gcc -o test *.c
3.Makefile中的变量
- 定义变量的基本语法
变量名 = 值列表
- 变量的使用
# 定义一个变量
var = main.c
# 变量的使用
$(var) 或者${var}
var = main.c
result:${var}
gcc -o result main.c
- Makefile中的四种变量的赋值方式
1.简单赋值::=
x:=foo
y:=$(x)b
x:=new
test:
@echo "y=>$(y)"
@echo "x=>$(x)"
# shell命令行中执行make test输出如下结果
#y=>foob
#x=>new
2.递归赋值
x=foo
y=$(x)b
x=new
test:
@echo "y=>$(y)"
@echo "x=>$(x)"
3.条件赋值:?=,如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。
4.追加赋值:+=,原变量用空格隔开的方式追加一个新值。
4.Makefile中自动化变量
5.makefile编写的三要素
在学习编写makefile文件以前,我们先来看makefile编写的三要素。
1.makefile编写的三要素:
- 目标
- 依赖
- 规则命令
2.示例
- 编写一个简单的makefile文件:
- 源文件hello.c如下所示,位于/root/practice目录下;head.h位于/root/practice/include目录下:
#include <stdio.h> #include <head.h> int returnMess(int val) { return val; } int main() { int a; #ifdef DEBUG printf("HelloWorld"); #endif printf("%d\n",returnMess(100)); return 0; }
- 在makefile文件下编辑如下内容:
app: hello.o gcc -o app hello.o hello.o: hello.c gcc -c -I ./include hello.c
- 然后执行make命令进行编译,生成可执行程序。
- 我们借用上诉示例来解释一下三要素:
注意: makefile的隐含规则:
- make时默认处理第一个目标。比如在上诉makefile中目标有两个。
6.变量的使用和常用函数的使用
我们发现,当改变源程序比如增加.c文件或者删除某个.c文件,上诉的makefile文件就需要做出大的改动。所以呢我们有必要学习变量的使用和常用函数的使用来对makefile做出改进。
1.变量的使用
- 为了简述变量的使用,我还是以上面的示例来说明。现在我们来举例说明使用变量的例子:
#自定义变量,变量名为var
var = hello.o
#变量名的使用:$(变量名)
app:$(var)
gcc -o app hello.o
hello.o: hello.c
gcc -c -I ./include hello.c
- 规则中使用的变量:下面这些变量只能在规则命令中使用,并且用于模式匹配规则。关于使用例子在后文中的makefile编写中有介绍。
- $@:代表目标
- $^:代表全部依赖
- $<:代表第一个依赖
- $?:代表第一个变化的依赖
2.函数的使用
- wildcard函数:可以进行文件匹配,比如匹配makefile当前所在目录下的所有后缀名为.c的源文件。语法规则是:
$(wildcard pattern)
,在makefile中他被展开为已经存在的、使用空格分开的、匹配此模式的所有文件列表。例如:
# 产生一个所有以.c、.cpp结尾的文件的列表,然后存入变量中
SOURCE = $(wildcard *.c *.cpp)
-
patsubst函数:用于匹配替换。包含三个参数,第一个表示需要匹配的文件,第二个表示用什么替换他,第三个是一个需要被处理的由空格分隔的列表。
-
为了简述wildcard函数的用法,我们举个例子。项目目录如下所示:
- makefile编写如下:
#获取与makefile文件同级目录下的所有后缀名为.c的文件 sourceFile = $(wildcard *.c) #获取所有的后缀名为.o的文件 objFiles1 = $(patsubst %.c, %.o ,$(sourceFile)) result:$(objFiles1) gcc -o result -I ./include $(objFiles1) %.o:%.c #变量的使用,$^,$@ gcc -c $^ -o $@ -I ./include test: #输出变量sourceFile和objFiles1的值 echo $(sourceFile) echo $(objFiles1) #定义伪目标,防止当前makefile文件所在目录下有与此目标名相同的文件造成歧义 .PHONY:clean clean: @rm -f *.o @rm -f result # 符号@表示在控制台不会打印rm -f *.o这样的信息
- 在上诉makefile文件中,为了验证wildcard函数和patsubst函数的使用是否成功,我们输出sourceFile和objFiles1的值。期间新增了一个目标test。
# 输出结果 make test echo add.c main.c sub.c add.c main.c sub.c echo add.o main.o sub.o add.o main.o sub.o
- make的结果如下:
make gcc -c add.c -o add.o -I ./include gcc -c main.c -o main.o -I ./include gcc -c sub.c -o sub.o -I ./include gcc -o result -I ./include add.o main.o sub.o