使用 -g 标志编译有什么缺点吗?

Are there any downsides to compiling with -g flag?

GDB 文档告诉我,为了调试编译,我需要让我的编译器生成调试符号。这是通过指定“-g”标志来完成的。

此外,GDB 文档建议我始终使用“-g”标志进行编译。这听起来不错,我也想这样做。

但首先,我想了解缺点。在生产代码中编译调试是否有任何惩罚?

我最感兴趣的是:

  1. GCC 作为首选编译器
  2. 红帽 Linux 作为目标 OS
  3. C 和 C++ 语言

(尽管也欢迎提供有关其他环境的信息)

非常感谢!

通常,添加调试信息会增加二进制文件的大小(或为调试信息创建额外的文件)。现在这通常不是问题,除非您通过慢速网络分发它。当然,这些调试信息可能会帮助其他人分析您的代码,如果他们想这样做的话。通常,-g 标志与 -O0(默认值)一起使用,它会禁用编译器优化并生成尽可能接近源代码的代码,以便调试更容易。虽然您可以将调试信息与启用的优化一起使用,但这确实很棘手,因为变量可能不存在,或者指令序列可能与源代码中的不同。这通常仅在需要分析仅在启用优化后发生的错误时才执行。当然,-O0的缺点是性能较差。

因此作为一个结论:通常在开发过程中使用 -g -O0,而对于分发或生产代码,只需 -O3

如果您使用 -g(在 最近 GCC or Clang 可以与优化标志一起使用,例如 -O2):

  • 编译时间较慢(链接会占用更多内存)
  • 可执行文件是一个更大的文件(参见 elf(5) and use readelf(1)...)
  • 可执行文件包含大量有关您的源代码的信息。
  • 你可以轻松使用GDB
  • 一些有趣的库,例如 Ian Taylor 的 libbacktrace, requires DWARF 信息(例如 -g

如果您不使用 -g,使用 GDB 调试器会更难(但可能)。

因此,如果您将二进制可执行文件传输给不了解您的源代码编写方式的合作伙伴,您需要避免-g

另请参阅 strip(1) and strace(1) 命令。

请注意,使用 -g 标志作为调试信息对 Ocaml, Rust

也有效

PS。最近的 GCC(例如 GCC 10 or GCC 11 in 2021) accept many debugger flags. With -g3 your executable carries more debug information (e.g. description of C++ macros and their expansion) that with -g or -g1. Of course, compilation time increases, and executable size also. In principle, your GCC plugin (perhaps Bismon in 2021, or those inside the source code of the Linux kernel)可以添加更多调试信息。实际上,除非可以改进调试器,否则您不会这样做。但是,GCC 插件(或某些 #pragmas)可以删除一些调试信息(例如删除 selected 函数集的调试信息)。