考虑以下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)
第一次跑步时,我得到:
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
没关系,但现在再次制作(不修改任何文件):
make: `../Obj/App/a.c.obj' is up to date.
现在,如果我修改文件a.c
Checking dependencies for ../Src/App/a.c
Compiling ../Obj/App/a.c.obj
target
未重新制作!
这就像我的文件a.c是目标,但它不是......有人可以解释我这里有什么问题吗?
如果我将包含删除到DEPS,我会观察到预期的行为......
由于
通过将@Beta所提到的包含放在最后,但现在我添加了目标clean并显示结果......
答案 0 :(得分:1)
我必须做一些实验才能确定,但我认为问题是:
-include $(DEPS)
...
all: target
您在第一个目标之前加入$(DEPS)
。因此,如果您修改a.c
,Make会发现它必须重建a.d
,那么因为它includes
该文件必须重新开始,现在a.c.obj
是早于all
的目标{1}}。
尝试将-include $(DEPS)
移动到makefile的末尾。
修改:
(两个小点:您的clean
规则不正确,因为它会尝试rm
一个目录,而我会make clean; make all
而不是make all
,因为我不确定承诺在所有情况下按给定顺序构建目标。)
是的,即使在运行DEPS
时,此makefile也会重建clean
。 makefile includes
这些文件并且有一个规则,所以如果它们丢失或过时,它必须重建它们并重新启动,无论目标是什么。解决这个问题的最佳方法是Advanced Auto-Dependency Generation;基本上,构建依赖项文件的命令都在%.obj
规则中,因此a.d
是构建a.c.obj
的副作用。这是一项复杂的技术,并不明显,但它的工作效果非常好。 (如果您尝试此操作并且无法进行设置,请告诉我们。)