【问题标题】:makefile: dependency not buildmakefile:依赖未构建
【发布时间】:2019-07-25 19:07:19
【问题描述】:

这个问题是在 MadScientist 的回答之后编辑的。查看原始 makefile 的历史记录,但问题仍然存在。

我有一个小的 makefile:

DEPFLAGS=-MD -Mo $(OUTDIR)/$*.Td
POSTCOMPILE=@mv -f $(OUTDIR)/$*.Td $(OUTDIR)/$*.d && touch $@
VPATH=../src
OUTDIR=../out
SOURCES:=$(notdir $(wildcard ../src/*.c))
OBJECTS:=$(SOURCES:%.c=$(OUTDIR)/%.o)

all: $(OBJECTS) $(OBJECTS:%.o=%.d)

$(OUTDIR)/%.o : %.c
$(OUTDIR)/%.o : %.c $(OUTDIR)/%.d
    @$(CC) $(DEPFLAGS) -c $< -o $@
    @$(POSTCOMPILE)

$(OUTDIR)/%.d : ;
.PRECIOUS: $(OUTDIR)/%.d

目录结构如下:

src
  contains file.c
out
  empty, after make: contains file.o and file.d
make
  contains the makefile

当我调用 makefile 时,一切正常,并生成了两个文件:file.ofile.d

但是,当我删除 file.d 时,什么也没有发生。我希望 make 找到 file.c 的缺失依赖项并开始重建。为什么没有发生?

Make 版本是为 Windows 7 下的 i386-pc-mingw32 构建的 3.81。

【问题讨论】:

    标签: makefile


    【解决方案1】:

    将文件标记为.PRECIOUS 并不会消除其“中间性”的所有方面。它所做的只是防止它被删除,但intermediate files的这个功能仍然有效:

    如果一个普通文件 b 不存在,并且 make 考虑一个依赖于 b 的目标,它总是创建 b 然后从 b 更新目标。但是如果 b 是一个中间文件,那么 make 就可以不用管它了。它不会打扰更新 b 或最终目标,除非 b 的某些先决条件比该目标更新或有其他原因更新该目标。

    这就是您的.d 文件未被重新创建的原因。为了重新创建它,您需要确保它不是中间文件。幸运的是,这很简单:您只需要在某处明确提及文件作为目标或先决条件。你可以这样做:

    all: $(OBJECTS) $(SOURCES:%.c=$(OUTDIR)/%.d)
    

    或者如果你喜欢这样:

    depends: $(SOURCES:%.c=$(OUTDIR)/%.d)
    

    如果您愿意,可以运行 make depends 来更新依赖文件。

    我只是顺便指出,这种管理依赖关系的方法被认为是过时的。有一种更好、更高级的方法可以在described here 等其他地方完成。

    【讨论】:

    • 感谢您的回答。不幸的是,它仍然不起作用。我根据您链接的页面更新了我的makefile(见问题)。我为我的全目标添加了一个先决条件。但是,当我删除依赖文件时,仍然没有任何反应。我错过了什么吗?
    • 我不知道,我刚刚尝试过,它对我有用,在 GNU/Linux 上使用 GCC 7.2 和 GNU make 4.2.1。我确实必须修改编译器参数以创建依赖项,因为您使用的那些对于这个版本的 GCC 不正确(-Mo 选项无法识别)。我使用了博客中的那些。此外,奇怪的是您实际上并没有 include 生成的 .d 文件,因为这是生成它们的全部意义,但这不应该导致您看到的问题。
    • 强烈建议您删除禁止打印脚本的@ 标志。你不会相信有多少问题是因为人们错误输入变量等而发生的,所以他们的命令行是错误的,但他们从来没有看到它,因为他们正在禁止打印他们的食谱。添加@,如果完成了(我不使用它),应该只在构建系统的所有其他方面已经工作和调试之后的最后一步添加。你也可以考虑这里提出的想法:make.mad-scientist.net/managing-recipe-echoing
    • 非常感谢。因为它对你有用,所以我用 4.2.1 替换了 make 3.8,瞧——它也对我有用:) 似乎是 make 3.8 的问题。顺便提一句。我包含了 dep 文件,我只是试图删除与我的问题无关的所有内容。
    【解决方案2】:

    (我会在这里成为一个可怕的死灵法师,但我遇到了同样的问题,发现实际问题不是答案或 cmets 中提到的)

    编译器生成的依赖规则,默认运动文件名,所有后缀替换为单个后缀.o 并删除路径。这与 makefile 中的规则模式不匹配。

    对于 gcc 4.x 及更高版本,正确的选项是

    $(OUTDIR)/%.o : %.c $(OUTDIR)/%.d
          @$(CC) -MF $(OUTDIR)/$*.Td -MT $@ -c $< -o $@
    

    Mo 标志不再存在,您只需要使用 MF 标志来指定依赖文件名。MT 标志允许为目标名称提供文字行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-23
      • 2015-11-07
      • 1970-01-01
      • 2012-10-04
      • 1970-01-01
      • 2012-09-28
      • 2018-04-05
      • 1970-01-01
      相关资源
      最近更新 更多