0

make is deleting files that have been created with my own rule (not an implicit one).

I have a makefile which works as expected, which is the following:


OBJ     = assert.o

DEP     = $(OBJ:.o=.d)

################################################################################
# target: dependencies
#   action

PHONY := all
all: $(subst .a.o,.a.o ,$(join $(OBJ:.o=.a.o),$(OBJ:.o=.so.o)))
    @:


%.d: $(SRC_DIR)/base/assert/%.c
    $(Q)mkdir -p        $(@D)/
    @echo   "   CC -M   build/tmp/base/assert/$@"
    $(Q)$(CC) $(CFLAGS_A) -MG -MT"$@" -MT"$*.a.s" -MT"$*.so.s" -M $< -MF $@
%.a.s: $(SRC_DIR)/base/assert/%.c
    $(Q)mkdir -p        $(@D)/
    @echo   "   CC  build/tmp/base/assert/$@"
    $(Q)$(CC) $(CFLAGS_A) -S $< -o $@
%.so.s: $(SRC_DIR)/base/assert/%.c
    $(Q)mkdir -p        $(@D)/
    @echo   "   CC  build/tmp/base/assert/$@"
    $(Q)$(CC) $(CFLAGS_SO) -S $< -o $@
%.o: %.s
    @echo   "   AS  build/tmp/base/assert/$@"
    $(Q)$(AS) $< -o $@

include $(DEP)


PHONY += clean
clean:
    $(Q)rm -f *.o *.s

################################################################################
# Declare the contents of the .PHONY variable as phony.
.PHONY: $(PHONY)

This makefile creates the files assert.d assert.a.s assert.so.s assert.a.o and assert.so.o and deletes none of them:

    CC -M   build/tmp/base/assert/assert.d
    CC  build/tmp/base/assert/assert.a.s
    AS  build/tmp/base/assert/assert.a.o
    CC  build/tmp/base/assert/assert.so.s
    AS  build/tmp/base/assert/assert.so.o

Then I have another makefile where I have to work with subdirectories, and I had to workaround a problem: % doesn't handle that well. The makefile is the following:

OBJ     = $(CURDIR)/tcp/client.o

DEP     = $(OBJ:.o=.d)
BOTH_OBJ    = $(subst .a.o,.a.o ,$(join $(OBJ:.o=.a.o),$(OBJ:.o=.so.o)))
#BOTH_ASM   = $(BOTH_OBJ:.o=.s)

################################################################################
# target: dependencies
#   action

PHONY := all
all: $(BOTH_OBJ)
    @:


$(CURDIR)/%.d: $(SRC_DIR)/base/socket/%.c
    $(Q)mkdir -p        $(@D)/
    @echo   "   CC -M   build/tmp/base/socket/$*.d"
    $(Q)$(CC) $(CFLAGS_A) -MG -MT"$@" -MT"$*.a.s" -MT"$*.so.s" -M $< -MF $@
$(CURDIR)/%.a.s: $(SRC_DIR)/base/socket/%.c
    $(Q)mkdir -p        $(@D)/
    @echo   "   CC  build/tmp/base/socket/$*.a.s"
    $(Q)$(CC) $(CFLAGS_A) -S $< -o $@
$(CURDIR)/%.so.s: $(SRC_DIR)/base/socket/%.c
    $(Q)mkdir -p        $(@D)/
    @echo   "   CC  build/tmp/base/socket/$*.so.s"
    $(Q)$(CC) $(CFLAGS_SO) -S $< -o $@
$(CURDIR)/%.o: $(CURDIR)/%.s
    @echo   "   AS  build/tmp/base/socket/$*.o"
    $(Q)$(AS) $< -o $@

include $(DEP)


PHONY += clean
clean:
    $(Q)rm -rf *.o *.s

################################################################################
# Declare the contents of the PHONY variable as phony.
.PHONY: $(PHONY)


#.PRECIOUS: $(BOTH_ASM)

However, for some reason, make decides that the intermediate files are not important here and removes them:

    CC -M   build/tmp/base/socket/tcp/client.d
    CC  build/tmp/base/socket/tcp/client.a.s
    AS  build/tmp/base/socket/tcp/client.a.o
    CC  build/tmp/base/socket/tcp/client.so.s
    AS  build/tmp/base/socket/tcp/client.so.o
rm /media/user/DataNTFS/Alex-dev/git/libalx/build/tmp/base/socket/tcp/client.a.s /media/user/DataNTFS/Alex-dev/git/libalx/build/tmp/base/socket/tcp/client.so.s

I found this. But I can see no difference between the two makefiles. It should remove the files either in both of them or none of them as far as I can see. Why is it removing the files in the second makefile only?


Uncommenting .PRECIOUS seems to prevent removal, but I'm not sure if I'm hiding something bad with it.

  • Aside: I'll add the .d files as a dependency for the .s files: If a header (e.g.: .../tcp/client.h) accidentally removes an `#include` which it does need, I'd like the compilation to break at that point. For that I need the .s to be recompiled, which can only be done if the .d is a dependency of the .s (the included contents of .d won't be enough to detect that a header is not used anymore). – alx - recommends codidact Feb 26 '20 at 13:34

1 Answers1

1

I forgot to add $(CURDIR)/ in the target names of the dependencies files generated by gcc.

This line solved that:

    $(Q)$(CC) $(CFLAGS_A) -MG -MT"$@" -MT"$(CURDIR)/$*.a.s" -MT"$(CURDIR)/$*.so.s" -M $< -MF $@

So the full rule is as follows:

$(CURDIR)/%.d: $(SRC_DIR)/base/socket/%.c
    $(Q)mkdir -p        $(@D)/
    @echo   "   CC -M   build/tmp/base/socket/$*.d"
    $(Q)$(CC) $(CFLAGS_A) -MG -MT"$@" -MT"$(CURDIR)/$*.a.s" -MT"$(CURDIR)/$*.so.s" -M $< -MF $@
  • It's not entirely clear to me: are you saying that this correction resolved your issue? – John Bollinger Feb 26 '20 at 12:53
  • 1
    @JohnBollinger It did. The .s files aren't removed anymore, and I don't understand much assembly, but they look good to me. And I haven't linked yet, but I guess the resulting library works. – alx - recommends codidact Feb 26 '20 at 13:01
  • 1
    The reason that they weren't removed before was that the dependencies (included via `include $(DEP)` listed the files in targets so they weren't considered intermediate. The reason it failed when you had the wrong paths is that the included files listed the wrong targets, so the ones in your makefile _were_ considered intermediate. Even if you hadn't seen this problem, you would have eventually realized that make was not rebuilding targets when it should, because the dependencies were wrong. – MadScientist Feb 26 '20 at 13:16