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

Una*_*nry 1 c++ linux shared-libraries shared-objects c++11

我从一个示例中的类创建一个共享库,我在这里获得了Linux上的C ++动态共享库。我想从创建的共享库中调用另一个共享库,然后在主程序中使用它。因此,我有myclass.so库,我想从myclass.so库中调用另一个库,例如anotherclass.so,然后在主程序中使用此myclass.so库。请问我如何做到这一点。

Mik*_*han 7

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

基本方法是简单地将所有库显式添加到程序的链接中,如果仅构建程序并链接由另一方构建的库,则这是通常的方法。

如果链接中的目标文件foo.o依赖于library libA.sofoo.o则应在libA.so链接序列之前。同样如果libA.so 要靠的libB.solibA.so应该先于libB.so。这是一个例子。

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

#ifndef SQUARE_H
#define SQUARE_H

double square(double d);

#endif
Run Code Online (Sandbox Code Playgroud)

方格

#include <square.h>
#include <cmath>

double square(double d)
{
    return pow(d,2);
}
Run Code Online (Sandbox Code Playgroud)

注意,该函数square调用pow在Standard标头中声明<cmath>并在数学库中定义libm

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

$ g++ -Wall -fPIC -I. -c square.cpp
Run Code Online (Sandbox Code Playgroud)

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

$ g++ -shared -o libsquare.so square.o
Run Code Online (Sandbox Code Playgroud)

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

立方体

#ifndef CUBE_H
#define CUBE_H

double cube(double d);

#endif
Run Code Online (Sandbox Code Playgroud)

多维数据集

#include <cube.h>
#include <square.h>

double cube(double d)
{
    return square(d) * d;
}
Run Code Online (Sandbox Code Playgroud)

看到函数cube调用square,所以libcube.so要依赖libsquare.so。与以前一样构建库:

$ g++ -Wall -fPIC -I. -c cube.cpp
$ g++ -shared -o libcube.so cube.o
Run Code Online (Sandbox Code Playgroud)

我们没有打扰到链接libsquarelibcube,即使libcube 依赖于libsquare,即使我们可以,因为我们正在建设libcube。因此,我们无需理会libmlibsquare。默认情况下,链接器将使我们链接包含未定义引用的共享库,这完全正常。它不会让我们用未定义的引用链接程序

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

main.cpp

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

int main()
{
    std::cout << cube(3) << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

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

$ g++ -Wall -I. -c main.cpp
Run Code Online (Sandbox Code Playgroud)

然后用户可以链接main.o所有三个所需的库,并确保列出依赖顺序链接器输入:main.olibcube.solibsquare.solibm.so

$ g++ -o prog main.o -L. -lcube -lsquare -lm
Run Code Online (Sandbox Code Playgroud)

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

我们已成功链接./prog,但:

$ ./prog
./prog: error while loading shared libraries: libcube.so: cannot open shared object file: No such file or directory
Run Code Online (Sandbox Code Playgroud)

它没有运行。这是因为运行时加载程序不知道在哪里找到libcube.so(或libsquare.so,尽管它没有那么远)。

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

$ export LD_LIBRARY_PATH=.
$ ./prog
27
Run Code Online (Sandbox Code Playgroud)

好。3立方= 27。

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

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

$ unset LD_LIBRARY_PATH
$ g++ -o prog main.o -L. -lcube -lsquare -lm -Wl,-rpath=.
Run Code Online (Sandbox Code Playgroud)

并重新运行:

$ ./prog
27
Run Code Online (Sandbox Code Playgroud)

-rpath与g ++一起使用,请为它加上前缀-Wl,因为它是链接器的一个选项ldg++前端无法识别:-Wl告诉g++该选项直接传递给ld


Min*_*nee 6

我想对@Mike 的回复补充一些观点。

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

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

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

然后,当您链接您的应用程序时,您可以执行以下操作:

g++ -o prog main.o -L. -lcube 
Run Code Online (Sandbox Code Playgroud)

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

g++ -o prog main.o -L. -lcube -Wl,-rpath-link=.
Run Code Online (Sandbox Code Playgroud)

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

  • 这是对最初解释的一个很好的补充。我只想补充一点,这种方法最好的一点是,未解析的链接将导致“共享未找到”错误,而不仅仅是“未定义的引用......”,这是迄今为止信息更丰富的...... (3认同)