tanascius
tanascius

Reputation: 53924

makefile: dependency not build

The question was edited after MadScientist's answer. See history for the original makefile, but the problem stays the same.

I have a small makefile:

DEPFLAGS=-MD -Mo $(OUTDIR)/$*.Td
POSTCOMPILE=@mv -f $(OUTDIR)/$*.Td $(OUTDIR)/$*.d && touch $@
VPATH=../src
OUTDIR=../out
SOURCES:=$(notdir $(wildcard ../src/*.c))
OBJECTS:=$(SOURCES:%.c=$(OUTDIR)/%.o)

all: $(OBJECTS) $(OBJECTS:%.o=%.d)

$(OUTDIR)/%.o : %.c
$(OUTDIR)/%.o : %.c $(OUTDIR)/%.d
    @$(CC) $(DEPFLAGS) -c $< -o $@
    @$(POSTCOMPILE)

$(OUTDIR)/%.d : ;
.PRECIOUS: $(OUTDIR)/%.d

Directory structure looks like:

src
  contains file.c
out
  empty, after make: contains file.o and file.d
make
  contains the makefile

When I call the makefile everything works fine and two files are generated: file.o and file.d

However, when I delete file.d nothing happens. I would expect that make finds a missing dependency for file.c and starts a rebuild. Why doesn't it happen?

Make version is 3.81 built for i386-pc-mingw32 under Windows 7.

Upvotes: 0

Views: 3486

Answers (2)

Swift - Friday Pie
Swift - Friday Pie

Reputation: 14589

(I'll be a horrific necromancer here, but I've ran into same problem, and found that actual issue isn't one mentioned in answer or comments here)

Dependency rule generated by compiler by default sports file name with ALL suffixes replaced by single suffix .o and path removed. Which doesn't match the pattern of rule in makefile.

For gcc 4.x and later correct options would be

$(OUTDIR)/%.o : %.c $(OUTDIR)/%.d
      @$(CC) -MF $(OUTDIR)/$*.Td -MT $@ -c $< -o $@

Mo flag no longer exist, you have to use only MF flag to specify dependency file name.MT flag allows to provide a literal line for target name.

Upvotes: 1

MadScientist
MadScientist

Reputation: 100781

Marking a file as .PRECIOUS does not remove all aspects of it's "intermediateness". All it does is prevent it from being deleted, but this feature of intermediate files is still in effect:

If an ordinary file b does not exist, and make considers a target that depends on b, it invariably creates b and then updates the target from b. But if b is an intermediate file, then make can leave well enough alone. It won’t bother updating b, or the ultimate target, unless some prerequisite of b is newer than that target or there is some other reason to update that target.

This is why your .d file is not recreated. In order for it to be recreated you need to ensure it's not an intermediate file. Fortunately this is trivial to do: you just need to mention the files explicitly somewhere as a target or prerequisite. You can do it like this:

all: $(OBJECTS) $(SOURCES:%.c=$(OUTDIR)/%.d)

Or if you prefer like this:

depends: $(SOURCES:%.c=$(OUTDIR)/%.d)

which would allow you to run make depends to update the dependency files, if you wanted to.

I'll just point out in passing that this method of managing dependencies is considered outdated. There's a better, more advanced way it can be done described here among other places.

Upvotes: 1

Related Questions