忽略生成的依赖项

Posted

技术标签:

【中文标题】忽略生成的依赖项【英文标题】:Make ignores generated dependencies 【发布时间】:2015-09-03 15:28:18 【问题描述】:

我正在尝试为我的项目编写一个自动生成源文件之间依赖关系的 Makefile。 Makefile如下:

CC = g++

CFLAGS  = -std=c++11 -Wfatal-errors -fdiagnostics-color=always
LDFLAGS = -lm -lfftw3

SRCDIR = src
OBJDIR = obj
DEPDIR = dep

SRCS = $(wildcard $(SRCDIR)/*.cpp)
OBJS = $(patsubst $(SRCDIR)/%.cpp,$(OBJDIR)/%.o,$(SRCS)) 
DEPS = $(patsubst $(SRCDIR)/%.cpp,$(DEPDIR)/%.d,$(SRCS))

PROG = whistle_recognition

$(PROG): $(OBJS)
    $(CC) $(CFLAGS) -o$(PROG) $(OBJS) $(LDFLAGS)

.PHONY: clean run

$(DEPS): $(DEPDIR)/%.d : $(SRCDIR)/%.cpp
    $(CC) $(CFLAGS) -MM $< -MF $@

$(OBJDIR)/%.o: $(SRCDIR)/%.cpp 
    $(CC) $(CFLAGS) -c $< -o $@

clean:
    rm -r $(OBJS) $(DEPS) $(PROG) 

run: $(PROG)
    ./$(PROG)

-include $(DEPS)

生成依赖项工作正常。但是,Make 会忽略它们。 假设我有一个包含头文件 quux.h 的文件 foo.cpp 。 如果 foo.cpp 更改 Make 重建 foo.o。但是,如果 quux.h 更改 Make 认为 foo.o 是最新的。我该如何解决这个问题?

编辑: 继承人更多信息:make -d whistle_recognition | grep signalscanner.d的输出:

Reading makefile 'dep/signalscanner.d' (search path) (don't care) (no ~ expansion)...
 Considering target file 'dep/signalscanner.d'.
  File 'dep/signalscanner.d' does not exist.
  Finished prerequisites of target file 'dep/signalscanner.d'.
 Must remake target 'dep/signalscanner.d'.
g++ -std=c++11 -Wfatal-errors -fdiagnostics-color=always -MM src/signalscanner.cpp -MF dep/signalscanner.d
Putting child 0xcda970 (dep/signalscanner.d) PID 2404 on the chain.
Live child 0xcda970 (dep/signalscanner.d) PID 2404 
 Successfully remade target file 'dep/signalscanner.d'.
Reading makefile 'dep/signalscanner.d' (search path) (don't care) (no ~ expansion)...
 Considering target file 'dep/signalscanner.d'.
  Finished prerequisites of target file 'dep/signalscanner.d'.
  Prerequisite 'src/signalscanner.cpp' is older than target 'dep/signalscanner.d'.
 No need to remake target 'dep/signalscanner.d'.

make -p whistle_recognition | signalscanner.o(缩短)的输出:

[...]
obj/signalscanner.o: src/signalscanner.cpp
[...]
signalscanner.o: src/signalscanner.cpp src/signalscanner.h src/frequencyanalyzer.h src/freqanalyzer_test.h src/wav_file.h src/signalscanner_test.h

还有问题:g++ 不包括目标的obj/-前缀...有没有办法通过模式替换来解决这个问题?

【问题讨论】:

你能显示dep/foo.d 文件吗?您是否看到 make 在 make -d 输出中包含 dep/foo.d 文件? make -p 输出是否在任何地方显示 quux.h?作为foo.o的部门? 这是dep/signalscanner.d 文件:signalscanner.o: src/signalscanner.cpp src/signalscanner.h \ src/frequencyanalyzer.h src/freqanalyzer_test.h src/wav_file.h \ src/signalscanner_test.h 嗯,依赖生成不正确。查看我的解决方案。 看到signalscanner.o?那不是你正在建造的。那就是问题所在。你需要解决这个问题。我不知道你是否可以让gcc 自动吐出带有前缀的目标,如果你必须sed/etc。将它放入文件中,但修复它,它会起作用。 -MT 的参数 gcc 可以在这里做你想做的事,但一般来说,Maxim Egorushkin 的答案更好。 【参考方案1】:

人们经常有这样的依赖生成规则,但它们确实是不必要的。

第一次构建项目时不需要依赖项,因为它会构建所有源代码。只有后续构建需要前一个构建的依赖项来检测需要重建的内容。

依赖只是编译的副产品。


生成的依赖包含对应.o文件的路径。由于在生成依赖项时未指定.o 输出路径,因此这些路径不正确。

以下解决方案将.d 文件与相应的.o 文件放在一起,这些.d 文件包含.o 的正确路径。它还可以一次性完成编译和依赖。

修复:

删除这些行:

$(DEPS): $(DEPDIR)/%.d : $(SRCDIR)/%.cpp
    $(CC) $(CFLAGS) -MM $< -MF $@
-include $(DEPS)

更新这些行:

DEPS = $(OBJS:%.o=%.d)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp 
    $(CC) -c $(CFLAGS) -MD -MP -o $@ $< 

在底部添加这些行:

ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif   

【讨论】:

@EtanReisner 为你添加了解释。 好多了,谢谢。虽然为了清楚起见,我可能会保留 DEPS 变量。 @EtanReisner 是的,DEPS 变量的变化更短。 我不得不在最后移除 if-guard,但它现在可以工作了。谢谢! @Vector 这是一个小优化,在清理时不包含依赖项。

以上是关于忽略生成的依赖项的主要内容,如果未能解决你的问题,请参考以下文章

npm install:有没有办法忽略 package.json 中的特定依赖项

RPM-安装一个RPM包,忽略依赖项

为啥 Pip 会忽略已配置的具有嵌套依赖项的存储库?

Maven 依赖项:从 settings.xml 获取最新的忽略存储库

忽略gradle beta依赖项

PHPUnit-函数依赖-数据提供-异常-忽略-自动生成