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

How does gcc decide which libraries to implicitly include?

本文关键字:包含哪 何决定 决定 gcc      更新时间:2023-10-16

关于这个问题:

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

问题不在于是否/何时应该使用断言,而在于编译器/链接器如何决定包含断言的所有必要开销。

我在另一篇文章中的原始问题:

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

在配置工具链时,作者决定默认情况下应链接到哪些库。

通常,这包括运行时启动/初始化代码和一个名为libc的库,其中包括 C 标准的实现,以及作者认为相关的任何其他代码(例如,libc 也可能实现 Posix、任何自定义板特定功能等(,对于嵌入式目标,链接到为目标实现 RTOS 的库并不罕见。

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

在assert((的情况下,它是一个标准的C宏/函数,通常在libc中实现.assert((如果失败,可能会打印到stdout,所以使用assert((可以拉入实现FILE*处理/缓冲,printf等的整个stdio工具,所有这些都是在libc中实现的。

如果您为链接阶段运行gcc -v,则可以看到 gcc 默认链接到的库。

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

运行哪些程序由 spec 文件决定(有一个隐式的,请参阅-dumpspecs开发人员选项(。顺便说一句,使用-v选项运行gcc会显示所涉及的实际程序。

定义assert宏(请参阅文件/usr/include/assert.h(以仅在NDEBUG不是定义的预处理器符号时才执行某些检入<assert.h>。在我的 Linux/Glibc 系统上,它可以从 C 标准库中调用__assert_failed内部函数。引用断言(3(文档:

如果宏NDEBUG是在上次<assert.h>定义 包括,宏assert()不生成任何代码,因此 什么都没有。

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

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

也许您想使用-ffreestanding进行编译以避免任何额外的库,甚至是标准库?

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

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

在静态库中找到的引用函数或变量与包含引用符号的整个对象文件一起包含在生成的可执行文件中。不包含引用符号的对象文件不会被拉入。

这绝不是 gcc 特有的。自古以来,链接器就是这样工作的。