【问题标题】:GCC dependency generation for a different output directory为不同的输出目录生成 GCC 依赖项
【发布时间】:2010-09-10 23:20:32
【问题描述】:

我正在使用 GCC 生成依赖文件,但我的构建规则将输出放入子目录中。有没有办法告诉 GCC 将我的子目录前缀放在它为我生成的依赖文件中?

gcc $(INCLUDES) -E -MM $(CFLAGS) $(SRC) >>$(DEP)

【问题讨论】:

    标签: c++ gcc makefile dependencies


    【解决方案1】:

    我假设您使用的是 GNU Make 和 GCC。首先添加一个变量来保存您的依赖文件列表。假设您已经拥有一个列出我们所有来源的文件:

    SRCS = \
            main.c \
            foo.c \
            stuff/bar.c
    
    DEPS = $(SRCS:.c=.d)
    

    然后在makefile中包含生成的依赖:

    include $(DEPS)
    

    然后添加这个模式规则:

    # automatically generate dependency rules
    
    %.d : %.c
            $(CC) $(CCFLAGS) -MF"$@" -MG -MM -MP -MT"$@" -MT"$(<:.c=.o)" "$<"
    
    # -MF  write the generated dependency rule to a file
    # -MG  assume missing headers will be generated and don't stop with an error
    # -MM  generate dependency rule for prerequisite, skipping system headers
    # -MP  add phony target for each header to prevent errors when header is missing
    # -MT  add a target to the generated dependency
    

    "$@" 是目标(: 左侧的东西),"$

    这里的技巧是通过两次添加 -MT 来生成具有两个目标的规则;这使得 .o 文件和 .d 文件都依赖于源文件及其头文件;这样,每当相应的 .c 或 .h 文件发生更改时,依赖文件就会自动重新生成。

    如果缺少头文件,-MG 和 -MP 选项可防止 make 崩溃。

    【讨论】:

    • 对我来说,在 gcc 4.1.2、gmake 3.8.1 上,如果头文件不存在,则配方 '$(CC) $(CCFLAGS) -MF"$@" -MG -MM -MP -MT"$@" -MT"$(<:.c>
    【解决方案2】:

    答案在GCC manual:使用-MT 标志。

    -MT target

    更改依赖生成发出的规则的目标。默认情况下,CPP 采用主输入文件的名称,删除任何目录组件和任何文件后缀,例如.c,并附加平台常用的对象后缀。结果就是目标。

    -MT 选项会将目标设置为您指定的字符串。如果您需要多个目标,可以将它们指定为 -MT 的单个参数,或使用多个 -MT 选项。

    例如,-MT '$(objpfx)foo.o' 可能会给出

    $(objpfx)foo.o: foo.c
    

    【讨论】:

    • -MT 不适用于我的 gcc 2.9.5,guest 应该在 3.x.x 以上可用
    • @checksum: ...2.9.5 不是 >14 年前发布的吗?
    • 是的,我在使用过时的构建平台维护遗留代码时发现了这一点。 :|它仍在使用 2.9.1.57(被称为 egcs 而不是 gcc),好消息是它对 4 个文件的依赖最小且小于 700k。 :) 不好的是它没有-MT 支持。 :(
    【解决方案3】:

    您可能会喜欢Don McCaughey's answer 的简短版本:

    SRCS = \
        main.c \
        foo.c \
        stuff/bar.c
    

    DEPS = $(SRCS:.c=.d)

    添加-include $(DEPS) 注意- 前缀,如果.d 文件尚不存在,它会消除错误。

    不需要单独的模式规则来生成依赖文件。只需将-MD-MMD 添加到您的正常编译行,.d 文件就会在编译源文件的同时生成。例如:

    %.o: %.c
         gcc $(INCLUDE) -MMD -c $< -o $@
    
    # -MD can be used to generate a dependency output file as a side-effect of the compilation process.
    

    【讨论】:

    • 顺便说一句,请务必避免将“包含”放在您的第一个目标上方。将它放在 Makefile 的底部是合乎逻辑的,因为这始终是放置依赖项的传统位置,当它们必须手工制作时!
    【解决方案4】:

    详细介绍DGentry's answer,这对我来说效果很好:

    .depend: $(SOURCES)
        $(CC) $(CFLAGS) -MM $(SOURCES) | sed 's|[a-zA-Z0-9_-]*\.o|$(OBJDIR)/&|' > ./.depend
    

    这也适用于只有一个依赖文件包含所有源文件的依赖规则的情况。

    【讨论】:

      【解决方案5】:

      好的,只是为了确保我的问题是正确的:我假设您有 test.c,其中包括 test.h,并且您想要生成 subdir/test.d(而 不是生成subdir/test.o) 其中subdir/test.d 包含

      subdir/test.o: test.c test.h
      

      而不是

      test.o: test.c test.h
      

      这就是你现在得到的。对吗?

      我无法想出一种简单的方法来完全按照您的要求进行操作。但是,查看 Dependency Generation Improvements,如果您想在生成 .o 文件的同时创建 .d 文件,您可以使用:

      gcc $(INCLUDES) -MMD $(CFLAGS) $(SRC) -o $(SUBDIR)/$(OBJ)
      

      (给定 SRC=test.cSUBDIR=subdirOBJ=test.o。)这将创建 subdir/test.o 和 subdir/test.d,其中 subdir/test.d 包含上述所需的输出。

      【讨论】:

        【解决方案6】:

        如果 GCC 有理由这样做,我不知道它是什么。我们最终将依赖输出通过sed 管道化,以将所有出现的&lt;blah&gt;.o 重写为${OBJDIR}/&lt;blah&gt;.o

        【讨论】:

          【解决方案7】:
          1. 如果您不将输出放在当前目录中,[GNU] make 会生气。您应该真正从构建目录运行 make,并使用 VPATH make 变量来定位源代码。如果你对编译器撒谎,它迟早会报复。

          2. 如果您坚持在其他目录中生成对象和依赖项,则需要使用-o 参数,如answered by Emile

          【讨论】:

            猜你喜欢
            • 2014-02-21
            • 1970-01-01
            • 2010-10-30
            • 2016-10-07
            • 2021-01-12
            • 1970-01-01
            • 2015-09-04
            • 2010-09-23
            • 1970-01-01
            相关资源
            最近更新 更多