make使用总结(7)-Makefile编写
上篇文章编写了最简单的Makefile文件。但它不够完美。首先当.h
文件发生变化时,需要先make clean
,再make
.这种方式在编译大型项目时会变得很慢,因为它需要先删除之前生成的所有中间文件,再重新创建中间文件。而理论上make只需要重新编译此.h
文件涉及到的相关源文件。然后链接程序就可以了。这节就是要解决这个问题。
优化make时的头文件依赖问题
例程源码链接:https://download.csdn.net/download/qq_23274715/13765780.
工程目录如下:
其中,文件common.c和main.c中引用了common.h文件。
Makefile文件如下:
# 文件说明
# 所有的文件都在同级目录下。包括`.h`文件,`.c`文件,以及生成的`.o`文件。
# 源文件需要手动的添加到Makefile文件中。
# 要生成的文件名
BIN := main
# 要编译的源文件
SRCS := main.c common.c
OBJS := $(SRCS:.c=.o)
DEPS := $(SRCS:.c=.d)
CC ?= gcc
INC_DIR ?= ./
WARNINGS ?= -Werror -Wall
CFLAGS ?= -O3 -g0 -I$(INC_DIR) $(WARNINGS)
LDFLAGS ?=
$(BIN):$(OBJS)
$(CC) -o $@ $^ $(LDFLAGS)
%.o:%.c
$(CC) $(CFLAGS) -c -o $@ $<
%.d: %.c
$(CC) -MM $(CFLAGS) $< | sed 's,\($*\)\.o[:]*,$(OBJPATH)/\1.o $@:,g' > $@
.PHONY:clean
clean:
rm -f *.o *.d $(BIN)
-include $(DEPS)
与之前的Makefile文件不同之处有三点:
- 新添加了一个变量
DEPS
. - 新添加了一个规则
%.d: %.c
。 - 在文件末尾引用了
-include $(DEPS)
.
我们现在的目标是当common.h文件发生变化时,make应该重新生成common.o.而要达到这一目的,我们就需要修改common.o的依赖。如下的代码。这样修改完成后,由于common.o
依赖于common.h
,所以当common.h
发生变化,make就会重新生成common.o
了。
common.o:common.c common.h
$(CC) $(CFLAGS) -c -o $@ $<
一般我们都是使用gcc
的-MM
选项自动化的实现这种依赖。如使用gcc -MM common.c
命令得到的输出为common.o: common.c common.h
。
上面新添加的规则%.d: %.c
就是使用上面的方式实现自动化依赖的。下面详细介绍这个规则
%.d: %.c
$(CC) -MM $(CFLAGS) $< | sed 's,\($*\)\.o[:]*,$(OBJPATH)/\1.o $@:,g' > $@
这个规则中的shell命令可以分为三部分:
$(CC) -MM $(CFLAGS) $<
.将它简化并实例化后为gcc -MM common.c
.就是用来输出common.o: common.c common.h
的内容信息。然后将其信息通过管道传给sed命令。sed 's,\($*\)\.o[:]*,$(OBJPATH)/\1.o $@:,g'
.这个sed命令作用是将内容common.o: common.c common.h
转化成common.o common.d: common.c common.h
。即添加common.d
目标,让它也依赖于common.c和common.h。为什么要这样做了?因为当common.c和common.h发生变化时,common.d文件也要更新。- 关于sed命令的使用详解
man sed
.
- 关于sed命令的使用详解
> $@
:将sed命令处理的结果common.o common.d: common.c common.h
重定向到文件$@
,即common.d文件中。
有了这个规则后,make就可以为每个c文件生成一个d文件,用来存放此c文件引用的头文件信息。最后使用-include $(DEPS)
将所有的d文件加载到此Makefile.这样我们的目就实现了。
关于技术交流
此处后的文字已经和题目内容无关,可以不看。
qq群:825695030
微信公众号:嵌入式的日常
如果上面的文章对你有用,欢迎打赏、点赞、评论。