在另一个共享库中使用共享库

时间:2018-08-14 11:01:46

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

我正在从我在这里C++ Dynamic Shared Library on Linux的示例中的类创建共享库。我想从创建的共享库中调用另一个共享库,然后在主程序中使用它。所以我有myclass.so库,我想从myclass.so库中调用另一个库,例如anotherclass.so,然后在主程序中使用此myclass.so库。请问我该怎么做。

4 个答案:

答案 0 :(得分:2)

可以通过多种方式将多个共享库添加到 程序的链接(如果要构建所有库和程序), 你自己。

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

如果链接中的对象文件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,该函数在 标准标头<cmath>,并在数学库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。 为此,我们无需费心将libcubelibm链接。默认情况下 链接器使我们可以链接包含未定义引用的共享库,并且它 非常正常。 不会让我们将程序与未定义的引用链接起来。

最后,我们使用以下库从该文件中编写一个程序:

main.cpp

libsquare

首先,将该源文件编译为#include <cube.h> #include <iostream> int main() { std::cout << cube(3) << std::endl; return 0; }

main.o

然后链接$ g++ -Wall -I. -c main.cpp 与所有三个必需的库,确保列出 链接器以依存关系顺序输入:main.omain.olibcube.solibsquare.so

libm.so

$ g++ -o prog main.o -L. -lcube -lsquare -lm 是一个系统库,因此无需告诉链接程序在哪里寻找 它。但是libmlibcube不是,所以我们需要告诉链接器寻找 它们放在当前目录(libsquare)中,因为它们就在这里。 .做到了。

我们已成功链接-L.,但是:

./prog

它没有运行。这是因为运行时 loader 不知道在何处找到$ ./prog ./prog: error while loading shared libraries: libcube.so: cannot open shared object file: No such file or directory (或libcube.so,尽管距离还远)。

通常,当我们构建共享库时,我们会将它们安装在加载程序的默认库之一中 搜索目录(与链接器的默认搜索目录相同),这些目录可用于任何程序,因此不会发生。但我不是 要在我的系统上安装这些玩具库,因此,作为变通办法,我将提示装载机在哪里寻找 通过在我的shell中设置libsquare.so为他们提供服务。

LD_LIBRARY_PATH

好。 3立方= 27。

将程序与未找到的共享库链接的另一种更好的方法 在标准系统库目录中是使用链接器的链接程序 $ export LD_LIBRARY_PATH=. $ ./prog 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 与g ++一起使用,请在其前面加上-rpath,因为它是链接器-Wl的选项, ld前端无法识别:g++告诉-Wl仅通过 选项直接进入g++

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

我想在@Mike的响应中添加一些要点。

由于您没有将 libcube 库与 libsquare 链接,所以您正在创建一种“不完整的库”。当我说不完整时,我的意思是,当您链接应用程序时,您必须同时将其链接到 libcube libsquare ,即使它没有直接使用 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 

尽管如此,这不会链接,因为链接器试图找到需要的库 libsquare 。您必须通过在链接命令中添加 -Wl,-rpath-link =。来精确确定其路径:

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

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