让 GNU Make 把中间文件放到独立目录
今天想把项目用的 Makefile 整理一下,主要是让 .o .a 等等这些中间文件生成到独立目录中去。做这项工作的过程中,发现了一些有趣的问题。
当然最头痛的要属路径名的斜杠转换问题,这里暂时不提。为了描述方便,暂且不考虑 windows 平台。
一开始我想到的方法是:把 .o 这些目标指定到一个独立目录下,比如写依赖关系:
$(ODIR)/%.o : %.c
然后让 gcc 直接编译到 $(ODIR) 下。
接着我发现一个问题,我需要用 gcc 去生成 .c 和 .h 的依赖关系文件。但是用 gcc -MM 生成后,格式都是
xxx.o : xxx.c xxx.h
这样的。也就是说,xxx.o 前面没有我需要的目标路径。
当然,我们可以用 sed 进一步处理这个文件。不过我查了下资料,想到另一个方案,即使用 GNU Make 的 vpath 指令。
注:网友 CHU Run-min 提醒,gcc 有个 -MT 选项可以修改 : 前面的 target 。不过如果想一次处理多个源,还是有一定的麻烦。
我们只需要在模式匹配前写上一句:
vpath %o $(ODIR)
那些,下面,符合 %.o 模式的目标,都会去 $(ODIR) 搜索。如此,我们便可以直接接着写:
%.o : %.c
这样的规则了。
下面的链接过程,可以直接写:
SRCS = xxx.c OBJS = $(OBJS:.c=.o)
a.exe : $(OBJS)
看起来好象一切正确,但是在实际工作中,老是有点问题。第一次运行 make 总报告说找不到某个 .o ;可是再运行一次 make 又正常了。
我仔细分析了一下,原来是这样的:
在依赖规则表建立起来的过程中, a.exe 依赖了若干 .o 文件,在上例中就是 xxx.o
因为当前路径以及 vpath 设置的 ODIR 中, xxx.o 均不存在,所以 make 企图构建 xxx.o ,于是它找到了
xxx.o : xxx.c
这条规则。对于这条规则,我让 gcc 直接把 xxx.o 生成到了 ODIR 下。但是这个发生在 a.exe 的依赖关系处理之前。 a.exe 的依赖表里填的仍然是当前目录下的 xxx.o
当第二次运行 make 的时候,由于 ODIR 下的 xxx.o 已存在,根据 vpath 的规则,make 觉得不需要重新构建 xxx.o 。并且, a.exe 的依赖表中, xxx.o 也被自动扩展到了 $(ODIR)/xxx.o 。这样,就可以正确构建 a.exe 了。
我想了个方法解决这个问题:让 a.exe 的构建过程不直接调用 gcc 的链接,而是用 make 重新跑一个伪目标。看起来是这样的:
all : $(OBJS) a.exe a.exe : $(OBJS) $(MAKE) exe exe : $(OBJS) $(LINK) a,exe $^
如此就能正常工作了。
在 Make 的时候,最先构建 OBJS 。然后试图构建 a.exe 。 而 a.exe 需要 fork 一份 make 构建自己。由于是新的子进程,所以这个时候 OBJS 都已经生成好。就不会有上面的问题。
当然,这不是个完美的解决方案,它依赖 all 后面的依赖次序。如果是多进程编译,还是有可能出问题的(仅是猜测,我觉得出不出问题会跟 make 具体实现有关,不过我自己试了是没有问题的)。等明天再想想更好的方法吧。
Comments
Posted by: 福利工口姬 | (11) April 16, 2014 04:20 PM
Posted by: chu | (10) September 15, 2009 04:51 PM
Posted by: yuer | (9) September 15, 2009 01:11 PM
Posted by: yuer | (8) September 15, 2009 01:09 PM
Posted by: ARM9 | (7) June 19, 2009 07:13 AM
Posted by: seatle | (6) March 30, 2009 03:14 PM
Posted by: func | (5) March 18, 2009 01:10 PM
Posted by: lxlxdw | (4) March 18, 2009 12:34 PM
Posted by: sc | (3) March 18, 2009 10:24 AM
Posted by: test | (2) March 18, 2009 09:58 AM
Posted by: et | (1) March 18, 2009 06:20 AM