【问题标题】:In C or C++, does the compiler do implicit linking?在 C 或 C++ 中,编译器是否进行隐式链接?
【发布时间】:2021-12-28 02:31:00
【问题描述】:

一些std-libexternal-libs或任何其他预编译的src代码如众所周知的头文件如何<iostream> 及其对应的目标文件static/dll链接我自己的应用程序自动?编译器是隐式地/在后台执行它还是像编译器预链表操作一样?

如果存在这样的案例我们如何使用它的功能在我们的协议中,有没有办法把我自己的objdllstatic-libsrc 文件通过编写一些 理想列表 em>特殊语法 无需更改每个初始目录,也无需 IDE 配置和外部软件的帮助,目标是在终端显式删除链接阶段,想要在 src-code 中做这个配置。

是否每个 std-lib 都有执行此类操作的直接/内联特殊 src 代码?如果有,那么我们如何利用它?或者,如果一切都由编译器/处理程序完成,并且如果它是泛型类型,那么您可以修改它,但问题较少,但它是由编译器修复的,并且讨厌强行修改/分叉它。如果已经有一种方法可以在不显式修改的情况下执行此操作,那么仅在您的 onw src-code/write-time 执行此操作,如该块语句的第一行所述:“是否每个 std-lib /external-lib 有一个直接/内联的特殊 src-code 执行这种操作?”。

// a.cpp
#include<iostream>

// there's no linking on iostream obj, src, dll, static-lib file
// love to have this kind of special features to our own none-std-lib/etc.
>c/cpp-compiler -c a.cpp
>c/cpp-compiler -o a a.o

注意:我的一些术语是基于我自己的经验,所以要小心并保持开放的心态。因为随着我在编码社区的成长,使用术语/标准的交流方式是一团糟,专门从低到另一个低,从高到另一个高级编程语言。

【问题讨论】:

  • 编译器有很多默认选项设置。与标准库的链接就是其中之一。
  • 尝试运行your-compiler -v -o a a.o。对于 gcc 和 clang,此输出的最后一部分将是它最终运行的实际低级链接命令。
  • @Barmar,是当前的编译器不能做到这一点,我想我有这个包含我自己的 self-proclaim-std-lib/src 的打包文件( zip/jar/etc...)将其设置为编译器中的参数,例如-std=c++*,但以这种方式-std-pkg=self-proclaim-std.zip 添加或更改std-lib。或者#include"mylib.h" @link(path/to/mylib.so)。甚至可以在写入时完成的编程语法。
  • GCC 编译器就像binutils 开源一样。您可以研究它的源代码并改进它。这将需要多年的工作。你可以开发你的GCC plugin。另请参阅DECODER 项目
  • 我不知道您所说的“写入时间”是什么意思。标准库没有链接到目标文件中。它链接到可执行文件中。如果您使用的是 GCC,您可以提供自定义规范文件;我很确定规范文件定义了自动链接库的名称和文件路径。在其他编译器中存在相同的工具,但形式完全不同。但为了避免一些-l 选项,要做的工作量很大。

标签: c++ linker compiler-construction


【解决方案1】:

这取决于你所说的“编译器”。

大多数现代工具链——包括 gcc、clang、Visual C++——都基于“编译然后链接”模型,包含多个组件。其中一个组件是预处理器(它对 C 或 C++ 源代码进行文本替换,以生成一些修改后的源代码),一个将预处理的源代码转换为目标文件的“编译器”,从源文件集生成库的实用程序,一个从一组目标文件和库生成可执行文件的链接器,以及 - 最后但并非最不重要的 - 一个协调其他组件执行的驱动程序。

工具链之间的细节不同 - 例如。 VC++ 做的事情与 gcc/g++ 或 clang 完全不同。概念相似。

在下文中,我将对 gcc 和 g++(在 gnu 编译器集合中)的作用进行非常简单化(不精确,省略细节)的讨论。

当您在命令行中使用 gcc 或 g++ 时,您实际上是在使用驱动程序,该程序协调了许多其他程序(预处理器、编译器、链接器等)的执行。根据您提供的选项,产生的结果会有所不同。例如gcc -E只完成源文件的预处理,g++ -c表示编译源文件产生目标文件后进程停止。如果用于生成可执行文件,驱动程序将使用链接器(嗯!)将目标文件和库链接在一起以生成可执行文件。

因此,如果您将 gcc 或 g++(您直接执行的程序)视为编译器,那么您可以声称编译器执行隐式链接。当用于创建可执行文件时,都执行链接器 - 并为其提供所需的信息(例如库的名称)。 gcc 自动链接 C 程序所需的库(例如 C 标准库),而 g++ 自动链接 C++ 程序所需的库(例如 C++ 标准库和 C 标准库的一部分)。

但是,如果您对编译器采取狭隘的看法——它只是将源文件转换为目标文件的程序——那么编译器就没有库的隐式链接。编排编译和链接的是驱动程序,而不是编排链接的编译器。

如果您阅读您最喜欢的工具链的文档,它将描述控制其功能的各种方法(源文件的扩展、设置、命令行选项、环境变量的值等)。通常可以灵活地进行仅预处理、仅编译、输出汇编程序、仅链接或完整的“编译多个源文件,然后将它们链接在一起以生成可执行文件”过程。

【讨论】:

    【解决方案2】:

    首先搜索标准库文件夹的某个顺序中的链接器搜索库。 默认情况下会加载一些默认库,例如 glibc。 这样您就不需要指定链接器来链接标准库。 Gcc 甚至有 not 与一些标准库链接的标志

    https://docs.oracle.com/cd/E19205-01/819-5262/auto29/index.html

    【讨论】:

    • 是的,这可以,但我需要一种在写入时的链接。这样我们就不会将它作为参数/选项显式链接到终端上的编译器。
    • 我没有尝试过,但你可以尝试阅读:unix.stackexchange.com/a/425349
    • @kobi:这个问题是关于添加库 paths-L 选项),就像你的答案一样。如果我理解正确,OP 正在询问添加库(-l 选项)。当然,我可能是错的。
    • 我链接到的评论建议添加到 /etc/ld.so.con 库,然后运行 ​​ldconfig。它还建议使用 -L 选项。
    【解决方案3】:

    请注意,虽然它不是标准的,但 Microsoft 的 Visual C++ 有一个基于 #pragma 的语言扩展,允许指定要在源中链接的文件:

    #pragma comment(lib, "yourfile.lib") // or yourfile.obj
    

    comment pragma 也可以用来指定一些其他的链接器命令行选项,例如:

    #pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='' publicKeyToken='6595b64144ccf1df' language=''"")

    请注意,可以通过这种方式指定的链接器选项列表相当有限,虽然还有一些其他合法的“注释”类型,但只有 lib 和链接器真正有意义。

    【讨论】:

      【解决方案4】:

      在 C 或 C++ 中,编译器是否进行隐式链接?

      由于“编译器”(被理解为生成最终可执行文件的链中的整个工具组)可以完全控制创建最终可执行文件,因此它会执行与编译的每个阶段相关的所有事情,包括隐式链接。

      一些 std-lib、external-libs 或任何其他预编译的 src 代码(例如众所周知的头文件及其相应的目标文件或静态/dll 库)如何自动链接到我自己的应用程序中?

      与链接任何其他库一样 - 链接器在库中搜索符号并使用它们。

      编译器是隐式地/在后台执行它还是类似于编译器预链表操作?

      是的(对于我使用的编译器)。

      但它对编译器非常具体。从 C++ 语言的角度来看,对编译器命令行选项没有要求。如果是compiler -needs-this-option-to-link-with-standard-library,它很好并且特定于该编译器。这是一个实施质量问题。用户肯定会希望 一些 事情通过合理的默认值隐式完成该编译器

      我们如何在我们的协议中使用它的功能,有没有办法通过编写一些特殊的语法将我自己的 obj/dll/static-lib/src 文件放入理想的列表中,而无需更改每个 i 的初始目录

      因为编译器是隐式执行的,所以你必须修改编译器。这在很大程度上取决于编译器,特定系统和特定编译器拥有非常特定的配置和构建设置。

      例如在带有 gcc 的 Linux 上,您可以使用 Enable AddressSanitizer by default in gcc 中的方法。也可以使用Custom gcc preprocessor中的方法,但是覆盖collect2阶段。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-02
        • 2011-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-01
        相关资源
        最近更新 更多