调用一些别人编写的动态链接库,但是一般都不提供源文件或.lib文件(有些比较抠门的第三方厂商就如此),就无法进行隐式连接
隐式连接(默认,无须声明)
通过在某些目录搜集共享目标的信息,让系统在程序启动时自动载入和连接共享库
显式链接
让程序自己通过库服务(libdl.so)来载入和连接到共享库
making the program load and link the shared objects thanks to some
用3个C++程序来演示这些服务,因为不严格地,C可以认为是C++的子集,出现的问题都是类似的
共享的库 定义了一个全局的C++类,在载入库时必须进行初始化,在卸载事必须销毁,这套子程序就叫做静态构造和析构器。共享库还提供了在C语言中的入口(在主程序中被调用), 因为C没有mangle(名称修饰)
试验1: 用ld建立共享库
1)在哪里寻找共享库,虽然 LD_LIBRAR_PATH据说是不被推荐使用的
$ export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:`pwd`
2)建立共享库
$ g++ -c base_shared.cc
$ ld -shared base_shared.o -o libbase_shared.so
3)建立主程序
$ g++ base.cc -L`pwd` -lbase_shared
/usr/bin/ld: a.out: hidden symbol `__dso_handle’ in /usr/lib/gcc/i486-linux-gnu/4.3.2/crtbegin.o is referenced by DSO
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: ld returned 1 exit status
因为引用了一个隐藏的符号__dso_handle,所以报错了
我们只好改用下面的共享库创建方式
$ g++ -shared base_shared.o -o libbase_shared.so
而不是像上面那样用 ld, 这个很重要
然后用下面的选项 编译 主程序
$ g++ base.cc -L`pwd` -lbase_shared
现在可以正常通过了,运行一下
$ ./a.oout
Constructor of toto
Main entry point
Shared lib entry point, toto’s var = 18
Destructor of toto
我们可以看到,主程序动态连接到共享库上了,并且 共享库的 静态 构造和解构器 会被自动调用
显示链接共享库
所谓显示,就是在主程序里面必须声明,Linux下是通过dlopen()来主动打开共享库
$ g++ -c base_shared.cc
$ ld -shared base_shared.o -o libbase_shared.so
$ g++ base1.cc -ldl
$ ./a.out
Main entry point
Loading shared lib…
./libbase_shared.so: undefined symbol: __dso_handle
运行时报错, 因为无法解析 __dso_handle
我们只好再次选择用gcc生成共享库,并修改编译选项
$ g++ -shared base_shared.o -o libbase_shared.so
$ g++ base1.cc -l dl
再试,就好了
实际上,我们之需要编译共享库就好了,不需要重新编译主程序,因为主程序的编译是没有问题的,是运行的时候报错
可以看到,在调用dlopen的时候,共享库被自动载入了构造过程
结论:
无论我们是显式还是隐式调用 共享库,要用g++ -shared来生成,而不是用ld -shared. 因为静态构造器 可能会 用到
If your shared library contains global or static objects with constructors, then make sure to use gcc -shared, not ld, to create the shared library. This will make sure that any processor-specific magic needed to execute the constructors is included.
gcc/g++链接注意事项
-l参数就是用来指定程序要链接的库,-l参数紧接着就是库名
那么库名跟真正的库文件名有什么关系呢?就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的头lib和尾.so去掉就是库名了
(用IDA反汇编出,也可以看到库名)
-L参数跟着的是库文件所在的目录名。不然,链接时会找不到库文件,除非你放到标准库目录(/lib,/usr/lib等)
PKG_CONFIG_PATH, 默认是 默认是/usr/lib/pkgconf
pkg-config base-shared –libs –cflags
生成共享库的另外一种方式
gcc -shared test.c -o libtest.so
-fpic 使输出的对象模块是按照可重定位地址方式生成的。(GOT)
LIBRART_PATH
g++-3.4 char.cpp -L. -lsystem-linux-golden -llanguage-linux-golden
1)函数要声明为extern
extern C {
}
反而不行
2) LD_LIBRARY_PATH要设置正确
export LD_LIBRARY_PATH=.