gcc 如何决定隐式包含哪些库?

How does gcc decide which libraries to implicitly include?

参考:

在一个小型微型嵌入式项目中,我发现编译后的代码比预期的要大得多。原来是因为我包含了使用 assert() 的代码。断言的使用在包含的代码中是合适的,但导致我编译的代码大小几乎翻了一番。

问题不在于 if/when 应该使用断言,而是 compiler/linker 如何决定包含断言的所有必要开销。

我原来的问题来自另一个post:

如果有人能向我解释 gcc 如何决定在调用 assert 时包含库函数,那将会很有帮助?我看到 assert.h 声明了一个外部函数 __assert_func。链接器如何知道从库中引用它而不是仅仅说 "undefined reference to __asert_func"?

gcc(或g++)命令只是一个驱动程序。它 运行 其他程序,包括编译器本身(cc1 用于 C 代码,cc1plus 用于 C++ 代码)以及汇编器和链接器。

是什么节目运行由spec file (and there is an implicit one, see the -dumpspecs developer option)决定。顺便说一句,使用 -v 选项的 运行ning gcc 显示实际涉及的程序。

assert 宏被定义(参见文件 /usr/include/assert.h)仅当 NDEBUG 不是已定义的预处理器符号时才在 <assert.h> 中进行一些检查。在我的 Linux/Glibc 系统上,它可以调用 C 标准库中的 __assert_failed 内部函数。引用 assert(3) 文档:

If the macro NDEBUG is defined at the moment <assert.h> was last included, the macro assert() generates no code, and hence does nothing at all.

一些项目在生产模式下使用-DNDEBUG它们的代码进行编译。

您应该阅读文档的 Invoking GCC 章节。

也许您想 compile with -ffreestanding 避免任何额外的库,即使是标准库?

在配置工具链时,作者决定默认应 link 编辑哪些库。

通常这包括 运行time startup/initializing 代码和名为 libc 的库,其中包含 C 标准的实现,以及作者认为相关的任何其他代码(例如 libc也可能实现 Posix、任何自定义电路板特定功能等),对于嵌入式目标,通常 link 到为目标实现 RTOS 的库。

您可以使用 gcc 的 -nodefaultlibs 标志在 linking 阶段忽略这些默认库。

对于assert(),它是一个标准的C macro/function,通常在libc中实现。如果失败,assert() 可能会打印到 stdout,因此使用 assert() 可以引入实现 FILE* handling/buffering、printf 等的整个 stdio 设施,所有这些都在 libc 中实现。

如果您 运行 gcc -v 在 linking 阶段,您可以看到默认情况下 gcc link 的库。

在您的嵌入式系统上,链接是静态的。静态链接的工作原理如下。

静态库是目标文件的存档。链接器分别考虑每个对象。

在静态库中找到的引用函数或变量包含在生成的可执行文件中,连同包含引用符号的整个目标文件。不包含引用符号的目标文件不会被拉入。

这绝不是 gcc 特有的。链接器从一开始就是这样工作的。