【问题标题】:How does gcc decide which libraries to implicitly include?gcc 如何决定隐式包含哪些库?
【发布时间】:2018-02-05 07:51:32
【问题描述】:

参考this question

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

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

我在另一篇帖子中的原始问题:

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

【问题讨论】:

    标签: c++ c gcc linker stm32


    【解决方案1】:

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

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

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

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

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

    【讨论】:

    • 这几乎就是它所做的。引入 stdio 和 printf 等...出于某种天真的原因,我认为链接器需要被告知所有要链接的库,包括 libc...
    【解决方案2】:

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

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

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

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

    【讨论】:

      【解决方案3】:

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

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

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

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-09
        • 2017-08-09
        • 1970-01-01
        相关资源
        最近更新 更多