1.从HelloWorld开始,假设有如下代码hello.c:
#include <stdio.h>
#include "a.h"
#include "b.h"
#include "hello.h"
int main(int argc, char* argv[])
{
printf("hello world.\n");
return 0;
}
接着上一篇简单理解makefile我们有如下式子:
CC = gcc
TARGET = hello
objs = hello.o a.o b.o
$(TARGET) : $(objs)
$(CC) -o $@ $^
在上述式子中只有修改源文件才会触发编译,修改头文件是没有反应的。
因为没有添加对.h文件的依赖关系,如下:
hello.o : a.h b.h hello.h
而在实际工作中代码的依赖关系是很复杂的,不可能每个都手动添加,因此需要自动推导依赖关系。
手动执行下述命令:
gcc -MM hello.c
输出结果为
hello.o: hello.c a.h b.h hello.h c.h d.h
2. 有了自动生成依赖关系的命令gcc -MM,我们就要想办法让makefile在执行的过程自动生成依赖,不过在此之前要先掌握两个表达式:
src = hello.c a.c b.c #定义变量src
objs = $(src:.c=.o) #将变量src中的.c替换成.o,等价于 objs = hello.o a.o b.o
src_d = $(src:.c=.d) #将变量src中的.c替换成.d
$(变量名:.c=.d) 就是我们要掌握的第一个表达式,第二个为include:
include $src_d #等价于 include hello.d a.d b.d
include表示makefile在执行时去寻找hello.d a.d b.d这3个makefile文件,遇到.d文件对应的依赖关系时,
则执行相应的命令,于是我们就有了一个初步的式子:
CC = gcc
TARGET = hello
src = hello.c a.c b.c
objs = $(src:.c=.o)
src_d = $(src:.c=.d)
$(TARGET) : $(objs)
$(CC) -o $@ $^
%.d : %.c
gcc -MM $< > $@ # 大于号表示把gcc -MM 命令的输出结果保存到$@即.d文件中
# 即为每一个c文件生成包含头文件和自身的依赖文件
include $(src_d)
3. 上述写法只有.c文件改变时对应的.d文件才会更新,如果需要.d也自动更新,则需要如下写法:
CC = gcc
TARGET = hello
src = hello.c a.c b.c
objs = $(src:.c=.o)
src_d = $(src:.c=.d)
$(TARGET) : $(objs)
$(CC) -o $@ $^
%.d : %.c
@set -e; rm -f $@; \
$(CC) -MM $< > $@.$$$-$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$-$ > $@; \
rm -f $@.$$$-$
include $(src_d)
4.上述$@.$$$-$中的短横线-要去掉,不加上一个符号连续4个$显示不出来。连续4个$会产生一个随机数,大家把rm -f这句话删掉就知道是啥意思了。
更多内容可以参看GNU make网站4.4节 http://www.gnu.org/software/make/manual/make.html#Reading