depending on directories in make [duplicate]

筅森魡賤 提交于 2019-12-21 09:03:16

问题


This is a followup to my earlier question: SO 4403861 because the suggested solutions broke the dependencies, making the makefile useless. I can't figure out why.

I am using gnu make 3.82 I have a rule that works if the obj directory has been created:

objdir:=../obj
$(objdir)/%.o: %.C
    $(COMPILE) -MM -MT$(objdir)/$(notdir $@) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
    $(COMPILE) -o $(objdir)/$(notdir $@ ) -c $<

However, if the obj directory isn't there, make fails. I wanted make to automatically create ../obj on demand, so I added what I thought was very simple:

$(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

When I do so, make always forces the compile, every time. Why? The mkdir should not happen unless there is no directory? Why are dependencies destroyed by this simple change?


回答1:


You also can try with Order-only prerequisites link

There is a similar example, of your question, available.

 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)



回答2:


As others have said, the problem is that a directory is considered "changed" whenever directory members are added or removed, so make sees your output directory changing all the time, and reruns all the compilations which you have told it depend on the output directory.

As an alternative to the workarounds described by others, recent GNU make versions have support for "order-only prerequisites". The description of order-only prerequisites in the manual includes an example of how to use them for directory creation.




回答3:


Some sort of sentinel file will solve this quite nicely. Allows you to write a single pattern rule to create all folders, does not have any rogue recompilation issues, and is -j safe.

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 $@



回答4:


As answered already, you cannot put a directory with output files as a dependency, because it is updated every time.

One solution (stated above) is to put a mkdir -p before each build, like this:

objdir:=../obj
$(objdir)/%.o: %.C
    @mkdir -p $(objdir) $(DEPDIR) ...
    $(COMPILE) -MM -MT$(objdir)/$(notdir $@) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
    $(COMPILE) -o $(objdir)/$(notdir $@ ) -c $<

But I don't love this solution, because it forces running an extra process lots and lots of times. However, knowing the reason for the error, there is another way:

exe: dirs $(OBJ)

In the primary target, the one building the executable, just insert a target dirs before the objects. Since it's hit in order:

dirs:
    @mkdir -p $(objdir) $(DESTDIR) ...

and this is only done once for the entire build, rather than once per file.



来源:https://stackoverflow.com/questions/4440500/depending-on-directories-in-make

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!