23

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

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

7 回答 7

44

我假设您使用的是 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

“$@” 是目标(: 左边的东西),“$<” 是先决条件(: 右边的东西)。表达式“$(<:.c=.o)”将 .c 扩展名替换为 .o。

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

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

于 2010-01-11T23:20:53.320 回答
21

答案在GCC 手册中:使用-MT标志。

-MT target

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

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

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

$(objpfx)foo.o: foo.c
于 2008-09-19T03:27:25.940 回答
12

您可能会喜欢Don McCaughey 回答的简短版本:

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.
于 2013-06-06T18:06:20.923 回答
3

详细说明DGentry 的答案,这对我来说效果很好:

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

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

于 2014-06-09T21:52:15.883 回答
2

好的,只是为了确保我的问题是正确的:我假设你有test.cwhich contains test.h,并且你想生成subdir/test.d(而不是生成subdir/test.o) where subdir/test.dcontains

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

而不是

test.o: test.c test.h

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

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

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

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

于 2008-09-18T22:38:41.063 回答
0

如果 GCC 有理由这样做,我不知道它是什么。我们最终通过sed管道依赖输出来重写所有出现的<blah>.oas ${OBJDIR}/<blah>.o

于 2008-09-18T21:52:21.863 回答
0
  1. 如果您不将输出放在当前目录中,[GNU] make 会生气。您应该真正从构建目录运行 make,并使用 VPATH make 变量来定位源代码。如果你对编译器撒谎,它迟早会报复。

  2. 如果您坚持在其他目录中生成对象和依赖项,则需要使用-o参数,正如Emile 所回答的那样

于 2008-09-18T23:10:51.143 回答