有不止一种方法可以将多个共享库添加到
程序的链接,如果您正在构建所有库和程序,
自己。
基本的方法是将所有库显式添加到
程序的链接,如果您只构建
由其他方构建的程序和链接库。
如果链接中的目标文件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
我们没有费心将libsquare 与libcube 联系起来,尽管libcube
取决于libsquare,即使我们可以拥有,因为我们正在构建libcube。
就此而言,我们没有费心将libm 与libsquare 联系起来。默认情况下
链接器将让我们链接一个包含未定义引用的共享库,它
完全正常。它不会让我们用未定义的引用链接一个程序。
最后让我们从这个文件中使用这些库制作一个程序:
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
然后将main.o 与所有三个必需的库链接,确保列出
链接器按依赖顺序输入:main.o、libcube.so、libsquare.so、libm.so:
$ g++ -o prog main.o -L. -lcube -lsquare -lm
libm 是一个系统库,因此无需告诉链接器在哪里寻找
它。但是libcube 和libsquare 不是,所以我们需要告诉链接器去寻找
它们在当前目录 (.) 中,因为那是它们所在的位置。 -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。