Consider the following makefile:
.SUFFIXES:
SRC:=../Src
OBJ:=../Obj
# Sources
SOURCES := $(SRC)/App/a.c $(SRC)/App/b.c $(SRC)/App/c.c
HEADERS := $(wildcard $(SRC)/App/*.h)
# Directories
INC_DIRS := $(SRC)/App
OBJ_INC_DIRS := $(INC_DIRS:$(SRC)/%=$(OBJ)/%)
# Objects
OBJECTS := $(SOURCES:$(SRC)%=$(OBJ)%.obj)
# Dependencies
DEPS := $(SOURCES:$(SRC)%.c=$(OBJ)%.d)
-include $(DEPS)
GCC_INCLUDES := $(foreach directory, $(INC_DIRS), -I$(directory))
all: target
target: $(OBJECTS)
touch target
#Objects
$(OBJ)%.c.obj: $(SRC)%.c
@echo Compiling $@
@touch $@
# Dependencies
$(OBJ)%.d: $(SRC)%.c
@echo Checking dependencies for $<
@gcc -MM $< $(GCC_INCLUDES) -MT '$(patsubst %.d,%.c.obj,$@)' -MT '$@' -MF '$@'
@[ ! -s $@ ] && rm -f $@
# Creating directory tree before checking dependencies
$(DEPS):|$(OBJ_INC_DIRS)
$(OBJ_INC_DIRS):
@mkdir $@
clean:
echo clean
@rm $(OBJ_INC_DIRS)
When running the first time, I get:
Checking dependencies for ../Src/App/a.c
Checking dependencies for ../Src/App/b.c
Checking dependencies for ../Src/App/c.c
clean
Compiling ../Obj/App/a.c.obj
Compiling ../Obj/App/b.c.obj
Compiling ../Obj/App/c.c.obj
touch target
It’s ok, but now, make again (without modifying any file):
make: `../Obj/App/a.c.obj' is up to date.
Now if I modify the file a.c
Checking dependencies for ../Src/App/a.c
Compiling ../Obj/App/a.c.obj
target isn’t remade !
It’s like my file a.c is the target but it isn’t… Can someone explain me what’s wrong here?
If I remove the include to the DEPS, I observe the expected behavior…
Thanks
EDIT
By putting the include at the end as mentioned by @Beta works but now I added the target clean and show the result…
I’ll have to do some experiments to be sure, but I think the problem is:
You include
$(DEPS)before the first target. So if you modifya.c, Make sees that it must rebuilda.d, then since itincludesthat file it must start over, and nowa.c.objis an earlier target thanall.Try moving
-include $(DEPS)to the end of the makefile.EDIT:
(Two small points: your
cleanrule is incorrect, since it tries torma directory, and I would domake clean; make allrather thanmake all, since I am not certain that Make promises to build targets in the given order in all cases.)Yes, this makefile will rebuild the
DEPSeven when runningclean. The makefileincludesthose files and has a rule for them, so if they are missing or out of date it must rebuild them and restart, no matter what the target is. The best way to deal with this is by Advanced Auto-Dependency Generation; basically, the commands that build dependency files go in the%.objrule, so thata.dis a side effect of buildinga.c.obj. It’s a sophisticated technique, not obvious, but it works beautifully. (Let us know if you try this and have trouble setting it up.)