0
votes

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.

1
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

1 Answers

1
votes

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