为不同的输出目录生成gcc依赖项

时间:2008-09-18 21:46:56

标签: c++ gcc makefile dependencies

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

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

7 个答案:

答案 0 :(得分:39)

我假设你正在使用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

“$ @”是目标(在左侧的东西),“$&lt;”是先决条件(在右侧的东西:)。表达式“$(&lt;:。c = .o)”用.o替换.c扩展名。

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

如果缺少头文件,-MG和-MP选项会使make吓坏。

答案 1 :(得分:18)

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

  

-MT target

     

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

     

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

     

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

$(objpfx)foo.o: foo.c

答案 2 :(得分:10)

你可能会喜欢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.

答案 3 :(得分:3)

详细介绍DGentry的答案,这对我来说非常有用:

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

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

答案 4 :(得分:1)

好的,只是为了确保我的问题是正确的:我假设你有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

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

我无法想出一个简单的方法来完全按照你的要求去做。但是,查看http://www.gnu.org/software/gcc/news/dependencies.html,如果要在生成.o文件时创建.d文件,可以使用

  

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包含所需的输出,如上所示。希望有所帮助。

答案 5 :(得分:0)

如果gcc有一个参数要做,我不知道它是什么。我们最终通过sed管道依赖输出,将所有出现的.o重写为$ {OBJDIR} /.o

答案 6 :(得分:0)

  1. 如果不将输出放在当前目录中,[GNU] make会生气。你真正应该做的是从build目录运行make,并使用VPATH make变量来定位源代码。如果你撒谎到编译器,它迟早会报复。

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