Makefile学习之路6——让编译环境更加有序
2017-05-04 15:57
204 查看
在大多项目中都会合理设计目录结构来提高维护性,在编译一个项目时会产生大量中间文件,如果中间文件直接和源文件放在一起,就显得杂乱而不利于维护。在为现在这个complicated项目编写makefile之前,我们先给出目录结构需求:
1.将所有的目标文件放在objs子目录中;
2.将最终生成的可执行程序放在exes子目录中;
在编译项目之前,需要将生成的文件目录准备好,可以手动创建,也可以通过编译Makefile创建。
为了将项目编译时所创建的文件分别放入objs和exes中,需要用到前面介绍的一个函数,addprefix。
这里运行之后就会在objs文件夹这种存放.o,在exes文件中存放可执行文件complicated。由于书上是把可执行文件放在当前目录的,所以它在clean加上了删除$(EXE),在我的Makefile中其实这句多余,因为把exes文件夹都删除了,在单独删除exes文件中的可执行文件没有意义,之所以没改,是为了提醒一下自己,这里完成了书上的不再赘述的任务O(∩_∩)O。
到这里 ,你可能觉得自己又get了一个新技能,但是,这却不是一个好的Makefile,比如,我们把foo.h更改为:
这里仅仅改变了foo函数的参数,从void变成了int,但是我们执行make:
注意,这里是在没有更改foo.h之前先make一次,然后在更改了foo.h之后再make,然后make提示居然没有任何事情可以做?奇怪吧,我们明明更改了函数声明不再匹配了啊,我们执行clean之后,再执行make:
这下make终于发现错误了,为什么第一次重新make的时候,make不发现错误呢?因为我们的Makefile中,并没有依赖foo.h,所以,我们可以更改Makefile如下:
其中红色部分为更改部分。
可以看到,我们先执行make生成目标文件,然后更改foo.h,再make,立即报错了。虽然这样可以解决问题,但是当项目复杂时,如果每一个头文件都要写入Makefile相应的规则中,那么将会是一个噩梦。看来我们还要寻找一个更好的办法。——当然,在后面的随笔中会提出的。
1.将所有的目标文件放在objs子目录中;
2.将最终生成的可执行程序放在exes子目录中;
在编译项目之前,需要将生成的文件目录准备好,可以手动创建,也可以通过编译Makefile创建。
1 .PHONY: all clean 2 3 MKDIR = mkdir 4 RM = rm 5 RMFLAGS = -rf 6 7 DIRS =objs exes 8 9 all:$(DIRS) 10 $(DIRS): 11 $(MKDIR) $@ 12 clean: 13 $(RM) $(RMFLAGS) $(DIRS)
为了将项目编译时所创建的文件分别放入objs和exes中,需要用到前面介绍的一个函数,addprefix。
1 .PHONY: all clean 2 3 MKDIR = mkdir 4 RM = rm 5 RMFLAGS = -rf 6 7 CC=gcc 8 9 DIR_OBJS=objs 10 DIR_EXES=exes 11 DIRS =$(DIR_OBJS) $(DIR_EXES) 12 EXE=complicated 13 SRCS=$(wildcard *.c) 14 OBJS=$(SRCS:.c=.o) 15 OBJS:=$(addprefix $(DIR_OBJS)/,$(OBJS)) 16 17 all:$(DIRS) $(DIR_EXES)/$(EXE) 18 $(DIRS): 19 $(MKDIR) $@ 20 $(DIR_EXES)/$(EXE):$(OBJS) 21 $(CC) -o $@ $^ 22 $(DIR_OBJS)/%.o:%.c 23 $(CC) -o $@ -c $^ 24 clean: 25 $(RM) $(RMFLAGS) $(DIRS) $(EXE)
这里运行之后就会在objs文件夹这种存放.o,在exes文件中存放可执行文件complicated。由于书上是把可执行文件放在当前目录的,所以它在clean加上了删除$(EXE),在我的Makefile中其实这句多余,因为把exes文件夹都删除了,在单独删除exes文件中的可执行文件没有意义,之所以没改,是为了提醒一下自己,这里完成了书上的不再赘述的任务O(∩_∩)O。
到这里 ,你可能觉得自己又get了一个新技能,但是,这却不是一个好的Makefile,比如,我们把foo.h更改为:
1 #ifndef __FOO_H 2 #define __FOO_H 3 4 void foo(int value); 5 6 #endif /*__FOO_H*/
这里仅仅改变了foo函数的参数,从void变成了int,但是我们执行make:
注意,这里是在没有更改foo.h之前先make一次,然后在更改了foo.h之后再make,然后make提示居然没有任何事情可以做?奇怪吧,我们明明更改了函数声明不再匹配了啊,我们执行clean之后,再执行make:
这下make终于发现错误了,为什么第一次重新make的时候,make不发现错误呢?因为我们的Makefile中,并没有依赖foo.h,所以,我们可以更改Makefile如下:
1 .PHONY: all clean 2 3 MKDIR = mkdir 4 RM = rm 5 RMFLAGS = -rf 6 7 CC=gcc 8 9 DIR_OBJS=objs 10 DIR_EXES=exes 11 DIRS =$(DIR_OBJS) $(DIR_EXES) 12 EXE=complicated 13 SRCS=$(wildcard *.c) 14 OBJS=$(SRCS:.c=.o) 15 OBJS:=$(addprefix $(DIR_OBJS)/,$(OBJS)) 16 17 all:$(DIRS) $(DIR_EXES)/$(EXE) 18 $(DIRS): 19 $(MKDIR) $@ 20 $(DIR_EXES)/$(EXE):$(OBJS) 21 $(CC) -o $@ $^ 22 $(DIR_OBJS)/%.o:%.c foo.h 23 $(CC) -o $@ -c $< 24 clean: 25 $(RM) $(RMFLAGS) $(DIRS) $(EXE)
其中红色部分为更改部分。
可以看到,我们先执行make生成目标文件,然后更改foo.h,再make,立即报错了。虽然这样可以解决问题,但是当项目复杂时,如果每一个头文件都要写入Makefile相应的规则中,那么将会是一个噩梦。看来我们还要寻找一个更好的办法。——当然,在后面的随笔中会提出的。
相关文章推荐
- linux 学习之路----搭建环境之交叉编译工具
- spark学习之路----配置spark编译源码,准备阅读环境
- VC++ 编译环境设置 学习之路vs2005
- Linux下编译环境及Makefile的学习笔记
- PHP学习之路(三)让我们开始环境搭建(搭建LMAP--基于Ubuntu11.04)
- 我的python学习之路----传递命令行参数给脚本及获取环境变量
- 一步一步建立linux交叉编译开发环境(学习笔记)
- RTEMS学习1—搭建编译环境,使用VMware运行hello worl
- VSTS2008 学习之路(1):配置开发环境
- Thrift 学习笔记1——Ubuntu环境下Thrift的安装、编译以及测试
- PHP学习之路(二)让我们开始环境搭建(Windows篇)
- Ant学习笔记——自己构建Ant编译环境
- 运用Autoconf和Automake生成Makefile的学习之路
- PHP学习之路(三)让我们开始环境搭建(搭建LMAP--基于Ubuntu11.04)
- PHP学习之路(二)让我们开始环境搭建(Windows篇)
- OK6410 Linux开发环境搭建--编译以及ubuntu的使用方法学习笔记
- Amlogic open linux 编译环境安装 ---学习笔记
- Java学习第一步:环境配置与编译第一个程序
- 学习笔记----编译搭建lnmp环境
- object-c学习(1)-window搭建object-c环境及编译