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



我正试图使用以下命令构建我的可执行文件(这取决于库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-lib的头文件足以构建它(即没有utils.so)

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

如果找到这样的文件,链接器将停止搜索并添加该文件对于链接的输入文件,无论它是否解析中的任何引用链接。链接器无法知道文件是否解析任何引用如果它没有输入文件。

如果找不到这样的文件,链接器将给出错误:cannot find -lutils。因为你让它找到libutils.{so|a},但它找不到。

你说:

我的可执行文件是一个共享库

但事实并非如此。您的编译和链接命令:

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

不是链接共享库的尝试。这是一种链接程序的尝试1

这将是一种链接共享库的尝试:

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

不能将程序与未解析的引用链接。但您可以链接共享库具有未解析的引用。

所以,你可以像这样链接一个libexecutable.so,或者你可以简单地像这样链接它:

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

这是两种不同的联系:如果它们成功了,就会产生不同的输出文件。

在第一个链接中,一些符号将(假设)解析为libutils.solibutils.a中提供的定义(以找到的为准),这将通过以下方式反映出来:

  • libutils.so被发现:libexecutable.so.dynamic部分包含一个DT_NEEDED表示对CCD_ 15的运行时依赖性的结构。libutils.so需要包含在任何包含libexecutable.so的链接中,但这种链接的输出文件本身将仅包含对libexecutable.so的运行时依赖项。

  • 发现libutils.alibexecutable.so本身包含所有符号的定义它使用由CCD_ 21中的对象文件定义的<可以在不需要CCD_ _x0032_3的情况下将sup=">2CCD_。

在第二个链接中,libexecutable.so.dynamic部分将而不是表示运行时依赖于libutils.so,文件将包含libutils.{so|a}提供的任何符号的定义。libutils.so将(再次)需要被包括在包括libexecutable.so的后续链接中,但是这种链接的输出文件将获得对libexecutable.solibutils.so的独立运行时依赖关系。

但是,如果在链接或任何链接中指定-lutils,而链接器找不到libutils.{so|a}在它的任何搜索目录中,你都会得到你观察到的错误,因为你告诉了链接器输入一个文件,只有在找到该文件时才能确定和实现该文件对链接的影响,而该文件却找不到。


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

[2] 请参阅静态库以了解为什么?

通常,ELF链接器需要链接的共享对象的足够精确的表示。它不一定是一个实际工作的共享对象,只需要它的一个足够接近的表示。一些绝对需要对象本身不可用的数据:

编译C程序时,对不完整类型的全局数据对象的引用不包含大小信息。链接器无法将对象放入数据段中,除非它从某个地方获得大小信息。默认情况下(为包括PIE在内的可执行文件编译时),由于编译器用于编译对全局数据对象的访问的重定位,因此需要在许多目标的数据段中分配对象
  • 类似地,如果链接编辑器的信息不足,它可能会错误地对齐全局数据对象
  • 许多库使用符号版本控制。只有当链接编辑器可以看到共享对象时,符号版本信息才可用。如果该信息丢失,链接编辑器将不会发出符号版本,这会指示动态链接器在运行时将符号绑定到基本版本,从而导致细微的错误
  • 但是,如果只使用C函数符号(而不是数据符号或C++所需的各种符号)并且目标库不使用符号版本控制,则可以使用存根库进行链接。这是一个库,它定义了您需要的所有函数,并具有适当的soname,但这些函数只是虚设的,实际上什么都不做。

    相关内容

    最新更新