如何正确组合 gcc 标志 -o 和 -MM?

How to combine gcc flags -o and -MM correctly?

在一个简单程序的编译和链接过程中,我遇到了一个我无法解释的怪异行为gcc

这个对我来说非常好用

cc -Wall -c -o obj/main.o src/main.c
cc -Wall -c -o obj/foo.o src/foo.c
cc -Wall -o bin/program obj/main.o obj/foo.o

但是,一旦我要求 gcc 创建依赖信息并将其存储在单独的文件中,链接器就会抛出错误:

cc -MM -MP -MF deps/main.d -Wall -c -o obj/main.o src/main.c
cc -MM -MP -MF deps/foo.d -Wall -c -o obj/foo.o src/foo.c
cc -Wall -o bin/program obj/main.o obj/foo.o
# obj/main.o: file not recognized: File truncated
# collect2: error: ld returned 1 exit status

我希望gcc 将依赖信息写入随-MF 语句提供的文件中。目标文件似乎以某种方式被修改,以至于链接器无法再读取它们。

有什么建议吗?

您的 object 文件被截断为 0 字节作为预处理器选项 side-effect -MM

参考the documentation of GCC's preprocessor options 并且您会看到 -MM-M 具有相同的效果,只是不针对任何系统生成依赖规则 headers #include-由翻译单位编辑。

对于 -M 选项,您将看到:

Instead of outputting the result of preprocessing, output a rule suitable for make describing the dependencies of the main source file...

还有:

Passing -M to the driver implies -E...

然后转到选项 -E 你会看到:

If you use the -E option, nothing is done except preprocessing.

(这实际上有点草率。真的应该这样写:“如果你使用 -E 选项,除了预处理之外没有完成 translation。”)

-o filename 选项指定无论请求何种输出文件 - 预处理代码、汇编、object 代码或二进制 - 都应写入 filename.

因此,例如,命令

cc -MM -MP -MF deps/main.d -Wall -c -o obj/main.o src/main.c

指示编译器(除其他事项外):-

  • 除预处理外不执行任何翻译(隐含 -E)。
  • 不输出预处理结果;改为输出依赖规则(通过 -MM
  • 不要将依赖规则写入输出文件(obj/main.o);改写 deps/main.d(通过 -MF deps/main.d

因此,输出文件 obj/main.o 被破坏并打开以接收输出 预处理; 没有预处理的输出;生成的依赖规则被写入 deps/main.d,当命令完成时 obj/main.o 关闭,包含 0 个字节。相同 事情发生在 obj/foo.o.

当然,这不是您想发生的事情。选项 -M-MM 仅对生成有用 独立于编译的依赖文件。但是你想要一个命令来生成一个依赖文件 deps/<name>.d一路翻译到object代码,输出在obj/<name>.o

要执行您想要的操作,请将命令中的选项 -MM 替换为 -MMD。在文档中,您将看到:

-MD

-MD is equivalent to -M -MF file, except that -E is not implied... Since -E is not implied, -MD can be used to generate a dependency output file as a side effect of the compilation process.

-MMD

Like -MD except mention only user header files, not system header files.

[我的重点]