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

Using a shared library in another shared library

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

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

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

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

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

最基本的方法就是将所有库显式添加到 link程序的年龄,如果您只构建 程序和 linking 由其他方构建的库。

如果您 link 年龄的目标文件 foo.o 依赖库 libA.so,则 在 link 年龄序列中,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

然后linksquare.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

我们没有费心 link libsquarelibcube,尽管 libcube 取决于 libsquare,即使我们可以,因为我们正在构建 libcube。 就此而言,我们没有费心去 link libmlibsquare。默认情况下 linker 会让我们 link 一个包含未定义引用的共享库,并且它 是完全正常的。它 不会 让我们 link 具有未定义引用的 程序

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

main.cpp

#include <cube.h>
#include <iostream>

int main()
{
    std::cout << cube(3) << std::endl;
    return 0;
}

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

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

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

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

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

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

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

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

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

中设置 LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH=.
$ ./prog
27

很好。 3 立方 = 27.

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

让我们重新[​​=158=] ./prog(首先从shell中删除LD_LIBRARY_PATH,这样它就不再有效了):

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

然后重新运行:

$ ./prog
27

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

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

由于您没有 link libcube 库和 libsquare,您正在创建一种 "incomplete library"。当我说不完整时,我的意思是当您 link 您的应用程序时,您必须 link 它同时包含 libcubelibsquare即使它不直接使用来自 libsquare.

的任何符号

最好直接用libsquare link libcube。此 link 将创建包含 NEEDED 条目的库,例如:

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

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

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

虽然,这不会 link,因为 linker 试图找到所需的库 libsquare。您必须通过将 -Wl,-rpath-link=. 添加到 linking 命令来精确其路径:

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

注意:对于运行时,您仍然必须使用 rpath 设置 LD_LIBRARY_PATH 或 link,如@迈克。