GNU Make 下创建目录的问题
很多时候,我们的 Makefile 在工作的时候,往往需要把中间文件放在独立目录中。这个独立目录一开始又没有创建出来。所以,Makefile 就有责任创建它们。
正确的创建目录,对于 Make 来说可是一个头痛的事情。
直观的写法是让目标依赖目录。比如:
foo.c : out/foo.o out/foo.o : out out : mkdir $@
这样做的问题在于,out 作为一个特殊文件(目录文件),时间戳是不受控的。
如果你删除或添加新文件到 out 目录下,都会更改 out 的时间戳,这会进一步的影响其依赖的目标。
我以前的解决方法是,放一个 probe 文件在目标目录下。这个文件的时间戳就是正常的,它在目录第一次被建立时建立,以后不再更改。
out/foo.o :foo.c out/.probe out/.probe : mkdir -p $(dir $@) && touch $@
这个方法我用了半年,总是有点不爽(因为那个多余的文件)。尤其是在 Windows 下时,dir 不会隐藏 . 开头的文件,让我不能眼不见心不烦。跟 svn 在目录目录下创建一个 .svn 目录一样的让人恼火。
今天仔细研究了一下,发现 GNU Make 3.80 以后的版本可以比较完美的解决这个问题。
方法是,把目录作为 order-only 的依赖。写法是在填依赖关系时加一个 |
out/foo.o : foo.c | out 或是写成两行 out/foo.o : foo.c out/foo.o : | out
out 前修饰了 | ,这样,只有在 out 不存在时,才会提前(在构建 out/foo.o 前)去构建。当 out 已经存在,out/foo.o 则不依赖 out 的时间戳。
如果一个项目需要大量创建中间目录,手写每个目录的构建规则肯定不合适。那么如何批量创建目录呢?
我的方法是,每次依赖一个中间目录时,就把目录名加到一个变量中。如:
MKDIRS += out
然后在 Makefile 的末尾:
$(sort $(MKDIRS)) : mkdir -p $@
不过,这样做还有一个缺陷。如果需要创建的目录有父子关系,一个更深层次的目录被创建出来后;随后创建的目录就会因为存在而创建失败。
固然,我们可以在 mkdir 前加上 - 忽略出错信息。但这不符合我的审美观。
我的解决方法是,过滤出有父子关系的目录,让浅的目录依赖深的目录,只在深层目录上真正 mkdir 。
代码如下:
MKDIRS := $(sort $(MKDIRS)) define SAFE_MKDIR CHILD := $(firstword $(filter $(1)/%,$(MKDIRS))) ifeq ($$(strip $$(CHILD)),) $(1) : $(MKDIR) $$(call pathname,$$@) else $(1) : | $$(CHILD) endif endef $(foreach dir,$(MKDIRS),$(eval $(call SAFE_MKDIR,$(dir))))
如果你想直接使用,请注意以上的空格和 Tab 的区别。
Comments
Posted by: www | (24) June 18, 2014 05:44 PM
Posted by: www | (23) June 18, 2014 05:43 PM
Posted by: 阿北 | (22) July 24, 2009 08:20 PM
Posted by: Jason | (21) July 24, 2009 02:49 PM
Posted by: 不去嫖 | (20) July 23, 2009 05:43 PM
Posted by: 阿北 | (19) July 23, 2009 09:40 AM
Posted by: __ | (18) July 19, 2009 08:29 AM
Posted by: 白沙 | (17) July 18, 2009 06:39 PM
Posted by: 骨头软件工作室 | (16) July 16, 2009 02:14 AM
Posted by: MJ | (15) July 14, 2009 02:04 PM
Posted by: 百度玩吧 | (14) July 14, 2009 10:57 AM
Posted by: TypeKey identity | (13) July 12, 2009 09:17 AM
Posted by: jacky | (12) July 11, 2009 10:56 PM
Posted by: 爱玩游戏 | (11) July 11, 2009 10:50 PM
Posted by: 皇冠投注网 | (10) July 11, 2009 01:34 AM
Posted by: 游戏资讯网 | (9) July 9, 2009 11:18 PM
Posted by: 坎钱的刀 | (8) July 9, 2009 03:46 PM
Posted by: 桂林旅游 | (7) July 8, 2009 10:10 PM
Posted by: object | (6) July 8, 2009 07:52 PM
Posted by: Tairan | (5) July 8, 2009 03:20 PM
Posted by: linghuye | (4) July 8, 2009 10:52 AM
Posted by: 空 | (3) July 8, 2009 10:36 AM
Posted by: 文 | (2) July 8, 2009 09:30 AM
Posted by: 路人甲 | (1) July 8, 2009 07:57 AM