本文转载自http://blog.youkuaiyun.com/li_wen01/article/details/57947242
最近看了陈皓的《跟我一起写Makefile》,里面介绍了很多的Makefile的知识,但是实例较少,我这里举例几个自动化变量使用,以便了解Makefile的强大功能。
关于自动化变量,在陈皓的文档里有下面的描述:
$@
表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。
$%
仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。
$<
依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
$?
所有比目标新的依赖目标的集合。以空格分隔。
$^
所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
$+
这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。
$*
这个变量表示目标模式中"%"及其之前的部分。如果目标是"dir/a.foo.b",并且目标的模式是"a.%.b",那么,"$*"的值就是"dir/a.foo"。这个变量对于构造有关联的文件名是比较有较。如果目标中没有模式的定义,那么"$*"也就不能被推导出,但是,如果目标文件的后缀是make所识别的,那么"$*"就是除了后缀的那一部分。例如:如果目标是"foo.c",因为".c"是make所能识别的后缀名,所以,"$*"的值就是"foo"。这个特性是GNU make的,很有可能不兼容于其它版本的make,所以,你应该尽量避免使用"$*",除非是在隐含规则或是静态模式中。如果目标中的后缀是make所不能识别的,那么"$*"就是空值。
假如我们有下面的程序:
如果不使用Makefile 文件,我们可以用下面的命令来执行:
gcc 的编译参数 -c 表示:只进程编译,不进行连接。-o 用来指定输出文件。gcc -o main main.o test1.o test2.o test3.o 命令表示 连接main.o test1.o test2.o test3.o 生成指定的文件main 可执行文件
如果使用Makefile 文件来做,最简单的可以是如下:
Makefile的一般书写方式是:
目标:依赖文件
生成目标文件的规则
英文的表述是:
targets: prerequisites
command
在Makefile文件中需要注意一点的就是:第一条规则中的目标将被确立为最终的目标。这里的最终目标也就是生成可执行文件main 编译运行结果如下:
进阶:
进一步简化Makefile文件,可以有如下的写法:
上面的Makefile文件中同时使用了$@ $^ $< 三个自动化变量
================================================
Makeflie 调试
“-n”
“--just-print”
“--dry-run”
“--recon”
比如上面的Makefile,如果执行 make -n 它的输出如下:
可以看到,make -n 指输出了make执行的命令,但是实际并没有进行编译工作。使用下面的参数,将输出更加多的Makefile信息
============================================
进阶版Makefile文件可以写成下面的这样:
这里需要注意的一点是:
.c .o:
gcc -c $<
这里表示的是,所有的.o文件都是依赖于相应的.c文件,这是Makefile的“ 后缀规则 ”,是一种比较古老的规则,可以使用“ 模式规则 ”来实现:
后缀规则和模式规则都属于Makefile的 隐含规则
后缀规则的Makefile执行结果如下:
模式规则的Makefile执行结果如下:
终极:
Makefile可以进一步简化,下面是简化后的版本:
第一行 := 表示前面的变量不能使用后面的变量,比如 EXE:= $(OBJS) 将会出错。
第二行 %.o: %.c 这个是模式规则
第三行 自动化变量$< 在模式规则中,表示依赖集合, $@表示目标集合
第四行 wildcard是扩展通配符,是Makefile的一个函数,这里是Makefile的函数调用。在这里是将当前目录下所有.c 结尾的文件展开
第五行 patsubst 是替换通配符,将SOURCE中以*c 结尾的名字替换为*.o 其实这里OBJ的值就是test1.o test2.o test3.o main.o 而SOURCE的值为:test1.c test2.c test3.c main.c
第六行 正常的Makefile书写,目标:依赖,规则,只是这里都是用变量代替了。实际执行的是:cc -g -o ./test test2.o test3.o main.o test1.o 其中-g参数表示有添加调试信息,也就是可以直接用GDB来调试生成的test 文件。
第七行 使用了伪目标clean,用来执行清除工作。
第八行 清除编译产生的中间文件。RM 的默认值是 rm -f 这里执行的是:rm -f *.o test
本文的测试代码 可以到这里下载:Makefile应用实例