【问题标题】:Using a shared library in another shared library在另一个共享库中使用共享库
【发布时间】:2019-01-21 05:18:28
【问题描述】:

我正在从一个示例中的类创建一个共享库C++ Dynamic Shared Library on Linux。我想从创建的共享库中调用另一个共享库,然后在主程序中使用它。所以我有 myclass.so 库,我想从 myclass.so 库中调用另一个库,比如 anotherclass.so,然后在主程序中使用这个 myclass.so 库。请对我如何做到这一点有任何想法。

【问题讨论】:

  • 一个库不使用另一个库。您从库 b 引用共享库 a 的头库。它们都可以共享。然后,当你链接你的可执行文件时,你在链接阶段包含两个 so 文件。

标签: c++ linux c++11 shared-libraries shared-objects


【解决方案1】:

如果您使用任何其他共享库,那么在您的库中,您的库用户也依赖于该库。在创建库时,您可以使用 -l 以便链接器具有共享库的概念,并且它将在需要时进行链接。 但是,当您将库作为依赖于其他库的方式交付时,您也需要将其与您的库一起导出,并提供一些环境变量或链接器标志以从指定路径(您的导出包)加载它。如果它的某些标准库函数用户可能从他的系统的某个其他库中获得定义,那么这不会导致任何差异,并且会导致灾难性的情况。

【讨论】:

    【解决方案2】:

    只需像在任何其他应用程序中使用它一样使用该库。您不必链接到anotherclass.so,只需链接到myclass.so

    但是,您必须使这两个库(myclass.so anotherclass.so)可用于以后的应用程序运行时。如果其中一个缺失,您将遇到运行时错误,就像使用任何其他应用程序一样。

    【讨论】:

      【解决方案3】:

      有不止一种方法可以将多个共享库添加到 程序的链接,如果您正在构建所有库和程序, 自己。

      基本的方法是将所有库显式添加到 程序的链接,如果您只构建 由其他方构建的程序和链接库。

      如果链接中的目标文件foo.o 依赖于库libA.so,则 foo.o 应在链接序列中位于 libA.so 之前。同样,如果libA.so 取决于libB.so 然后libA.so 应该在libB.so 之前。这是一个插图。

      我们将从文件中创建一个共享库libsquare.so

      square.h

      #ifndef SQUARE_H
      #define SQUARE_H
      
      double square(double d);
      
      #endif
      

      square.cpp

      #include <square.h>
      #include <cmath>
      
      double square(double d)
      {
          return pow(d,2);
      }
      

      请注意,函数square 调用pow,它在 标准头 &lt;cmath&gt; 并在数学库中定义,libm

      将源文件square.cpp编译成与位置无关的目标文件 square.o:

      $ g++ -Wall -fPIC -I. -c square.cpp
      

      然后将square.o链接到共享库libsquare.so

      $ g++ -shared -o libsquare.so square.o
      

      接下来,我们将从这些文件中创建另一个共享库libcube.so

      cube.h

      #ifndef CUBE_H
      #define CUBE_H
      
      double cube(double d);
      
      #endif
      

      cube.cpp

      #include <cube.h>
      #include <square.h>
      
      double cube(double d)
      {
          return square(d) * d;
      }
      

      看到函数cube调用square,所以libcube.so会 取决于libsquare.so。像以前一样构建库:

      $ g++ -Wall -fPIC -I. -c cube.cpp
      $ g++ -shared -o libcube.so cube.o
      

      我们没有费心将libsquarelibcube 联系起来,尽管libcube 取决于libsquare,即使我们可以拥有,因为我们正在构建libcube。 就此而言,我们没有费心将libmlibsquare 联系起来。默认情况下 链接器将让我们链接一个包含未定义引用的共享库,它 完全正常。它不会让我们用未定义的引用链接一个程序

      最后让我们从这个文件中使用这些库制作一个程序:

      ma​​in.cpp

      #include <cube.h>
      #include <iostream>
      
      int main()
      {
          std::cout << cube(3) << std::endl;
          return 0;
      }
      

      首先,将该源文件编译为main.o

      $ g++ -Wall -I. -c main.cpp
      

      然后将main.o 与所有三个必需的库链接,确保列出 链接器按依赖顺序输入:main.olibcube.solibsquare.solibm.so

      $ g++ -o prog main.o -L. -lcube -lsquare -lm
      

      libm 是一个系统库,因此无需告诉链接器在哪里寻找 它。但是libcubelibsquare 不是,所以我们需要告诉链接器去寻找 它们在当前目录 (.) 中,因为那是它们所在的位置。 -L. 就是这样做的。

      我们已成功关联./prog,但是:

      $ ./prog
      ./prog: error while loading shared libraries: libcube.so: cannot open shared object file: No such file or directory
      

      它没有运行。那是因为运行时 loader 不知道在哪里可以找到libcube.so(或libsquare.so,虽然它没有走那么远)。

      通常,当我们构建共享库时,我们会将它们安装在加载器的默认值之一中 搜索目录(与链接器的默认搜索目录相同),它们可供任何程序使用,因此不会发生这种情况。但我不是 将在我的系统上安装这些玩具库,作为一种解决方法,我将提示加载程序在哪里查看 通过在我的 shell 中设置 LD_LIBRARY_PATH 来为他们服务。

      $ export LD_LIBRARY_PATH=.
      $ ./prog
      27
      

      很好。 3 立方 = 27。

      另一种更好的方式将程序与不存在的共享库链接 在标准系统库目录中是使用链接器的链接程序 -rpath=DIR 选项。这会将一些信息写入可执行文件以告诉 它应该在尝试之前在DIR 中搜索所需共享库的加载器 默认位置。

      让我们以这种方式重新链接./prog(首先从外壳中删除LD_LIBRARY_PATH,使其不再有效):

      $ unset LD_LIBRARY_PATH
      $ g++ -o prog main.o -L. -lcube -lsquare -lm -Wl,-rpath=.
      

      然后重新运行:

      $ ./prog
      27
      

      要将-rpath 与g++ 一起使用,请在其前面加上-Wl,因为它是链接器ld 的一个选项, g++ 前端无法识别:-Wl 告诉 g++ 只是通过 直接选择ld

      【讨论】:

        【解决方案4】:

        我想为@Mike 的回复补充几点。

        由于您没有将 libcube 库与 libsquare 链接,因此您正在创建一种“不完整的库”。当我说不完整时,我的意思是当您链接您的应用程序时,您必须将它与 libcubelibsquare 链接,即使它不直接使用来自 libsquare 的任何符号

        libcube 最好直接与 libsquare 链接。此链接将创建带有 NEEDED 条目的库,例如:

        readelf -d libcube.so
        Tag        Type                         Name/Value
        0x0000000000000001 (NEEDED)             Shared library: [libsquare.so]
        

        然后,当您链接您的应用程序时,您可以:

        g++ -o prog main.o -L. -lcube 
        

        虽然,这不会链接,因为链接器会尝试定位 NEEDED 库 libsquare。您必须通过将 -Wl,-rpath-link=. 添加到链接命令来精确其路径:

        g++ -o prog main.o -L. -lcube -Wl,-rpath-link=.
        

        注意:对于运行时,您仍必须设置 LD_LIBRARY_PATH 或与 @Mike 提到的 rpath 链接。

        【讨论】:

        • Т这是对最初解释的一个很好的补充。我只想补充一点,这种方法最好的一点是,未解决的链接会导致“未找到共享”错误,而不仅仅是“未定义的对...的引用”,后者提供的信息要多得多...
        • @Minee 谢谢。但是,如果最后我只想要一个发送给第三方(没有 libsquare.so)的大型 .so 库(cube.so)怎么办?我该怎么做?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-17
        • 2011-08-27
        • 2015-09-30
        • 2013-10-25
        • 2020-11-18
        • 1970-01-01
        相关资源
        最近更新 更多