前言:
makefile 的基本语法是 目标:依赖+命令。 很显然makefile的一个主要工作就是表达目标的依赖性。抓住“依赖”才是抓住makefile的核心。
假如有如下:
main.c def.h 其中 def.h定义一些简单的数据结构供main.c使用,也就是说main.c依赖于def.h
CC = gcc
SRCS := $(wildcard *.c)
OBJS := $(patsubst %.c,%.o, $(SRCS))
all: main
main: $(OBJS)
$(CC) -o main $(OBJS)
clean:
rm -f *.o
大家看看有没有什么问题?真正运行你就发现.c对.h的依赖关系,导致.h的变化不会导致makefile执行发生变化。
如果是一个比较大型的工程,你必需清楚哪些C文件包含了哪些头文件,并且,你在加入或删除头文件时,也需要小心地修改Makefile,这是一个很没有维护性的工作。
为了避免这种繁重而又容易出错的事情,我们可以使用C/C++编译的一个功能。大多数的C/C++编译器都支持一个“-M”的选项,即自动找寻源文件中包含的头文件,并生成一个依赖关系。
例如,如果我们执行下面的命令:
cc -M main.c
其输出是:
main.o : main.c defs.h
如何利用这个输出结果,将编译器的这个功能如何与我们的Makefile联系在一起呢?
目标(可执行文件或者是库文件)---> .o ----> .c --->.h
其实我们可以写出这样的makefile。
1:在makeifle中写出[.d]文件和[.c]文件的依赖关系,(见下面%.d: %.c部分),
2:让make自动更新或自成[.d]文件,($(CC) -M $(CPPFLAGS) $< > $@.$$$$;),
自动更新使用编译器的自动推倒功能
3:把[.d]包含在我们的主Makefile中(include $(SRCS:.c=.d)).
CC = gcc
SRCS := $(wildcard *.c)
OBJS := $(patsubst %.c,%.o, $(SRCS))
all: main
%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
include $(SRCS:.c=.d)
main: $(OBJS)
$(CC) -o main $(OBJS)
clean:
rm -f *.o *.d main
妙处1:%.d: %.c 虽然有点复杂 其实是
main.o main.d : main.c defs.h
妙处2:include $(SRCS:.c=.d.
把main.o main.d : main.c defs.h替换到文件中。此时我们就可以看到main.o依赖于.c和.h的规则了,
-->.h
总结:
makefile通过包含编译器的推导出来的依赖性输出的结果,将其作为makefile的内容来实现自动推导。