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

时间:2017-08-28 05:34:55

标签: c++ c gcc linker stm32

参考this question

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

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

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

如果有人能够向我解释当调用assert时gcc如何决定包含库函数会有所帮助?我看到assert.h声明了一个外部函数__assert_func。链接器如何知道从库中引用它而不是仅仅说“未定义引用__asert_func”?

3 个答案:

答案 0 :(得分:6)

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

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

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

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

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

答案 1 :(得分:4)

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

运行的程序由spec file决定(有一个隐含程序,请参阅-dumpspecs developer option)。顺便说一句,使用gcc选项运行-v会显示所涉及的实际程序。

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

  

如果在NDEBUG最后一次定义宏<assert.h>     包含,宏assert()不生成代码,因此          什么都没有。

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

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

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

答案 2 :(得分:2)

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

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

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

这绝不是gcc特有的。林克斯从一开始就以这种方式工作。