Makefile学习之路7————让编译环境更加有序
在大多项目中都会合理设计目录结构来提高维护性,在编译一个项目时会产生大量中间文件,如果中间文件直接和源文件放在一起,就显得杂乱而不利于维护。在为现在这个complicated项目编写makefile之前,我们先给出目录结构需求:
1.将所有的目标文件放在objs子目录中;
2.将最终生成的可执行程序放在exes子目录中;
在编译项目之前,需要将生成的文件目录准备好,可以手动创建,也可以通过编译Makefile创建。
.PHONY: all clean MKDIR = mkdir RM = rm RMFLAGS = -rf DIRS =objs exes all:$(DIRS) $(DIRS): $(MKDIR) $@ clean: $(RM) $(RMFLAGS) $(DIRS)
为了将项目编译时所创建的文件分别放入objs和exes中,需要用到前面介绍的一个函数,addprefix。
.PHONY: all clean MKDIR = mkdir RM = rm RMFLAGS = -rf CC=gcc DIR_OBJS=objs DIR_EXES=exes DIRS =$(DIR_OBJS) $(DIR_EXES) EXE=complicated SRCS=$(wildcard *.c) OBJS=$(SRCS:.c=.o) OBJS:=$(addprefix $(DIR_OBJS)/,$(OBJS)) all:$(DIRS) $(DIR_EXES)/$(EXE) $(DIRS): $(MKDIR) $@ $(DIR_EXES)/$(EXE):$(OBJS) $(CC) -o $@ $^ $(DIR_OBJS)/%.o:%.c $(CC) -o $@ -c $^ clean: $(RM) $(RMFLAGS) $(DIRS) $(EXE)
这里运行之后就会在objs文件夹中存放.o,在exes文件中存放可执行文件complicated。由于书上是把可执行文件放在当前目录的,所以它在clean加上了删除$(EXE),在我的Makefile中其实这句多余,因为把exes文件夹都删除了,在单独删除exes文件中的可执行文件没有意义,之所以没改,是为了提醒一下自己,这里完成了书上的不再赘述的任务O(∩_∩)O。
到这里 ,你可能觉得自己又get了一个新技能,但是,这却不是一个好的Makefile,比如,我们把foo.h更改为:
#ifndef __FOO_H #define __FOO_H void foo(int value); #endif /*__FOO_H*/
这里仅仅改变了foo函数的参数,从void变成了int,但是我们执行make:
注意,这里是在没有更改foo.h之前先make一次,然后在更改了foo.h之后再make,然后make提示居然没有任何事情可以做?奇怪吧,我们明明更改了函数声明不再匹配了啊,我们执行clean之后,再执行make:
这下make终于发现错误了,为什么第一次重新make的时候,make不发现错误呢?因为我们的Makefile中,并没有依赖foo.h。
在改进之前,我们分析一下make为什么不能发现foo.h的更改并对项目进行重新编译。下图是现有的Makefile所表达的依赖关系树。从图中我们并不能找到foo.h文件的身影,也就是说,从make的角度来看它并不知道foo.h的存在,因而也不能侦测到foo.h文件的变动并对项目进行重新编译。
所以,我们可以更改Makefile如下:
.PHONY: all clean MKDIR = mkdir RM = rm RMFLAGS = -rf CC=gcc DIR_OBJS=objs DIR_EXES=exes DIRS =$(DIR_OBJS) $(DIR_EXES) EXE=complicated SRCS=$(wildcard *.c) OBJS=$(SRCS:.c=.o) OBJS:=$(addprefix $(DIR_OBJS)/,$(OBJS)) all:$(DIRS) $(DIR_EXES)/$(EXE) $(DIRS): $(MKDIR) $@ $(DIR_EXES)/$(EXE):$(OBJS) $(CC) -o $@ $^ $(DIR_OBJS)/%.o:%.c foo.h $(CC) -o $@ -c $< clean: $(RM) $(RMFLAGS) $(DIRS) $(EXE)
其中红色部分为更改部分。
其中的改动非常小,即将foo.h文件作为每一个.o文件的先决条件。在这个Makefile中,首次使用了自动变量$<。
用$<的目的是为了只将.c文件作为gcc的输入内容。
可以看到,我们先执行make生成目标文件,然后更改foo.h,再make,立即报错了。虽然这样可以解决问题,但是当项目复杂时,如果每一个头文件都要写入Makefile相应的规则中,那么将会是一个噩梦。看来我们还要寻找一个更好的办法。
----当然,之后的博客会提到。
欢迎加入作者的小圈子
扫描下方左边二维码加入QQ交流群,扫描下方右边二维码关注个人微信公众号并,获取更多隐藏干货,QQ交流群:859800032 微信公众号:Crystal软件学堂
作者:Liu_Jing bilibili视频教程地址:https://space.bilibili.com/5782182 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在转载文章页面给出原文连接。 如果你觉得文章对你有所帮助,烦请点个推荐,你的支持是我更文的动力。 文中若有错误,请您务必指出,感谢给予我建议并让我提高的你。 |