为什么 ld 需要我的可执行文件所依赖的库?

Why does ld need library that my executable depends on?

我正在尝试使用以下命令构建我的可执行文件(依赖库 utils.so)

g++ -L/path/to/libutils -lutils -I/path/to/utils_headers executable.cpp -o executable

其实我没有utils.so - 只有utils库的头文件。

我遇到错误:

ld: cannot find -lutils

链接器是否真的需要访问我的可执行文件所依赖的所有库才能构建我的可执行文件?如果确实如此,那么我想知道为什么它需要访问它们。

我的可执行文件是一个共享库。我确定 utils 库的头文件足以构建它(即没有 utils.so)。

一般来说,ELF linker 需要足够准确地表示 linked 中的共享对象。它不必是实际工作的共享对象,只要足够准确即可它的密切代表。一些东西绝对需要对象本身不可用的数据:

  • 编译C程序时,对不完整类型的全局数据对象的引用不包含大小信息。 linker 无法将对象放入数据段,除非它从某处获得大小信息。默认情况下(为可执行文件编译时,包括 PIE)需要在许多目标上的数据段中分配对象,因为编译器使用重定位来编译对全局数据对象的访问。
  • 同样,link 编辑器如果信息不足,可能会错误地对齐全局数据对象。
  • 许多库使用符号版本控制。仅当 link 编辑器可以看到共享对象时,符号版本信息才可用。如果缺少该信息,link 编辑器将不会发出符号版本,这会指示动态 linker 在 运行 时将符号绑定到基础版本,从而导致细微的错误.

但是,如果您只使用 C 函数符号(不是数据符号,或 C++ 需要的各种符号)并且目标库不使用符号版本控制,您可以使用存根库进行 linking。这是一个库,它定义了您需要的所有功能并具有适当的 soname,但这些功能只是假人,实际上并没有做任何事情。

默认情况下,linkage 选项 -lutils 会指示 linker 进行搜索, 首先在指定的库搜索目录 (-Ldir) 中,然后 在其默认搜索目录中,对于任一文件 libutils.so ( 共享库)或 libutils.a(静态库),更喜欢 libutils.so 如果它们都在同一个搜索目录中。

如果找到这样的文件,linker 将停止搜索并添加该文件 linkage 的输入文件,它是否解析了任何引用 link年龄。 linker 不知道文件是否解析了任何引用 如果没有输入文件。

如果没有找到这样的文件,linker 会给出错误:cannot find -lutils。因为 你告诉它去寻找 libutils.{so|a} 但它找不到。

你说:

My executable is a shared library

但事实并非如此。您的编译-link 命令:

$ g++ -L/path/to/libutils -lutils -I/path/to/utils_headers executable.cpp -o executable

不是 link 共享库的尝试。这是一个尝试link的程序。1

这将是 link 共享库的尝试:

$ g++ -shared -I/path/to/utils_headers -o libexecutable.so executable.cpp -L/path/to/libutils -lutils

您不能 link 具有未解析引用的程序。但是你可以 link 一个共享库 有未解决的引用。

所以,你可以 link 一个 libexecutable.so 那样,或者你可以 link 它只是像:

$ g++ -shared -I/path/to/utils_headers -o libexecutable.so executable.cpp

这是两个不同的 linkages:如果他们成功了,他们会产生不同的输出文件。

在第一个 link 时代,一些符号将(假设)解析为 libutils.solibutils.a 中提供的定义 (以找到的为准),这将反映为:

  • libutils.so 被发现: libexecutable.so.dynamic 部分包含一个 DT_NEEDED 表示对 libutils.so 的运行时依赖性的结构。 libutils.so 将需要包含在包含 libexecutable.so 的任何 linkage 中,但此类 linkage 的输出文件本身将仅包含对 [=20] 的运行时依赖性=].

  • libutils.a 被发现: libexecutable.so 本身包含所有的 definitions符号 它使用由 libutils.a.2 libexecutable.so 中的目标文件定义的,可能会包含在后续 linkages 中,而不需要 libutils.{so|a}.

在第二个 linkage 中,libexecutable.so.dynamic 部分将 not 表示运行时间 依赖 libutils.so 文件将包含 libutils.{so|a} 提供的任何符号的定义。 libutils.so 将(再次)需要包含在包含 libexecutable.so 的后续 linkage 中,但是这样一个 linkage 的输出文件将获得独立的运行时依赖性libexecutable.solibutils.so

但是,如果您在 linkage 或任何 linkage 中指定 -lutils,并且 linker 找不到 libutils.{so|a} 在它的任何搜索目录中,然后你会得到你观察到的错误,因为你告诉 linker 输入一个文件,其对 linkage 的影响只有在找到该文件时才能确定和实施 - 而找不到它。


[1] 可能会失败的尝试,因为 它在对象之前消耗库 引用它们的文件

[2] 参见 static-libraries 了解 为什么。