不同输出目录的 GCC 依赖项生成
-
01-07-2019 - |
题
我正在使用 GCC 生成依赖文件,但我的构建规则将输出放入子目录中。有没有办法告诉 GCC 将我的子目录前缀放入它为我生成的依赖文件中?
gcc $(INCLUDES) -E -MM $(CFLAGS) $(SRC) >>$(DEP)
解决方案
答案就在 海湾合作委员会手册:使用 -MT
旗帜。
-MT target
更改依赖项生成发出的规则的目标。默认情况下,CPP 采用主输入文件的名称,删除任何目录组件和任何文件后缀,例如
.c
, ,并附加平台的常用对象后缀。结果就是目标。一个
-MT
选项会将目标设置为您指定的字符串。如果您想要多个目标,可以将它们指定为单个参数-MT
, ,或使用多个-MT
选项。例如,
-MT '$(objpfx)foo.o'
可能会给$(objpfx)foo.o: foo.c
其他提示
我假设您正在使用 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 崩溃。
您可能会喜欢这个简短的版本 唐·麦考伊的回答:
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.
详细介绍 D金特里的回答, ,这对我来说效果很好:
.depend: $(SOURCES)
$(CC) $(CFLAGS) -MM $(SOURCES) | sed 's|[a-zA-Z0-9_-]*\.o|$(OBJDIR)/&|' > ./.depend
这也适用于只有一个依赖文件包含所有源文件的依赖规则的情况。
好吧,只是为了确保我的问题是正确的:我假设你有 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
这就是你现在得到的。是对的吗?
我无法想出一种简单的方法来完全满足您的要求。然而,看着 依赖项生成改进, ,如果你想创建 .d
在生成 .o 文件时,您可以使用:
gcc $(INCLUDES) -MMD $(CFLAGS) $(SRC) -o $(SUBDIR)/$(OBJ)
(鉴于 SRC=test.c
, SUBDIR=subdir
, , 和 OBJ=test.o
.) 这将创建 subdir/test.o 和 subdir/test.d,其中 subdir/test.d
包含如上所述的所需输出。
如果海湾合作委员会有理由这样做,我不知道那是什么。我们最终通过管道输出依赖项 sed 重写所有出现的 <blah>.o
作为 ${OBJDIR}/<blah>.o
.
如果您不将输出放在当前目录中,[GNU] make 会生气。您确实应该从构建目录运行 make,并使用 VPATH make 变量来定位源代码。如果你对编译器撒谎,它迟早会报复。
如果您坚持在其他目录中生成对象和依赖项,则需要使用
-o
论证,如 埃米尔回答.