这是我之前问题的后续内容:SO 4403861因为建议的解决方案打破了依赖关系,使makefile无用。我无法弄清楚原因。
我正在使用gnu make 3.82 我有一个规则,如果已创建obj目录,该规则有效:
objdir:=../obj
$(objdir)/%.o: %.C
$(COMPILE) -MM -MT$(objdir)/$(notdir $@) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
$(COMPILE) -o $(objdir)/$(notdir $@ ) -c $<
但是,如果没有obj目录,则make失败。我希望make能够根据需要自动创建../obj,所以我添加了我认为非常简单的内容:
$(objdir)/%.o: %.C $(objdir)
$(COMPILE) -MM -MT$(objdir)/$(notdir $@) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
$(COMPILE) -o $(objdir)/$(notdir $@ ) -c $<
$(objdir):
if [ ! -d $(objdir) ] ; then mkdir $(objdir) ; fi
当我这样做时,每次都要强制编译。为什么?除非没有目录,否则不应该发生mkdir?为什么这种简单的改变会破坏依赖性呢?
答案 0 :(得分:23)
您也可以尝试使用仅订购先决条件link
您的问题有一个类似的例子。
OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
$(OBJDIR)/%.o : %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
all: $(OBJS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir $(OBJDIR)
答案 1 :(得分:11)
正如其他人所说的那样,问题是每当添加或删除目录成员时,目录都会被视为“已更改”,因此make会看到您的输出目录一直在变化,并重新运行您告诉它的所有编译依赖于输出目录。
作为其他人描述的变通方法的替代方案,最近的GNU make版本支持“仅限订单的先决条件”。 The description of order-only prerequisites in the manual包含一个如何使用它们创建目录的示例。
答案 2 :(得分:4)
某种类型的sentinel 文件可以很好地解决这个问题。允许您编写单个模式规则来创建所有文件夹,没有任何恶意重新编译问题,并且-j
是安全的。
OBJDIR := objdir/
OBJS := $(addprefix ${OBJDIR},foo.o bar.o baz.o)
all: ${OBJS}
${OBJDIR}%.o : %.c ${OBJDIR}.sentinel
${COMPILE.c} ${OUTPUT_OPTION} $<
# A single pattern rule will create all appropriate folders as required
.PRECIOUS: %/.sentinel # otherwise make (annoyingly) deletes it
%/.sentinel:
mkdir -p ${@D}
touch $@
答案 3 :(得分:3)
如前所述,您不能将包含输出文件的目录作为依赖项,因为它每次都会更新。
一个解决方案(如上所述)是在每次构建之前放置一个mkdir -p,如下所示:
objdir:=../obj
$(objdir)/%.o: %.C
@mkdir -p $(objdir) $(DEPDIR) ...
$(COMPILE) -MM -MT$(objdir)/$(notdir $@) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
$(COMPILE) -o $(objdir)/$(notdir $@ ) -c $<
但是我不喜欢这个解决方案,因为它会强制运行额外的过程很多次。但是,知道错误的原因,还有另一种方法:
exe: dirs $(OBJ)
在主要目标中,构建可执行文件的目标,只需在对象之前插入目标目录。因为它按顺序命中:
dirs:
@mkdir -p $(objdir) $(DESTDIR) ...
这只对整个构建执行一次,而不是每个文件执行一次。