共享库C/C++

共享库---共享对象的集合

1.产生原因

随着软件规模的越来越大,我们的函数越来越多,为了简化这些极为庞大的共享对象。所以就将这些函数根据相应的需求规划成一些集合,进行一些处理生成共享库文件,这样可以极大的减少函数的数量便于管理和升级。

2。共享库的版本

更新:

兼容更新。所有的更新只是在原有的共享库基础上添加一些内容,所有的接口都保持不变。

不兼容跟新。改变了所有的原有接口,更新后原有的程序可能不能运行

就是ABI 接口改变,一般二进制接口改变,程序是不能运行的。

3。ABI改变情况以及兼容性分析

。导出函数的行为发生改变,也就是说调用这个函数以后产生的结果与以前不一样,不再满足旧版本规定的函数行为准则。

。导出函数被删除

。导出数据的结构发生变化,比如共享库定义的结构变量的结构发生改变。

。当然一般改变结构体,例如给结构体增加一些项目只要是动态分配的都是没有太大影响的。

。导出函数的接口发生变化,如函数返回值,参数被更改

。对于C++来说,ABI变化就是灾难性的

如果需要开发一个C++的共享库,需要注意以下事项。

不要在接口中使用虚函数,万不得已时,不要随意删除,添加或在子类中添加新的实现函数,这样会导致类的函数表发生变化。

不要改变任何成员变量的位置和类型

不要删除非内嵌的Public 或 protected 成员函数

不要将非嵌入式的成员函数改变成内嵌成员函数

不要改变成员函数的访问权限

不要在接口中使用模版

最重要的是,不要改变接口的任何部分或干脆不要使用C++作为共享库接口,使用C吧少年!

4。共享库的版本名

Linux有一套较为完善的命名机制。

Libname.so.x.y.z

这就是我们经常看到的共享库的标准命名形式,最前面是lib 中间是库的名字 最后是 .so 后缀

最后是它的版本号。

X:主版本号,不同版本号之间是不能兼容的。改变后需要重新编译。

Y:次版本号,表示库的增量升级,即增加一些新的接口符号,且保持原来的接口不变,一般是高的次版本号向后兼容底的版本号。

Z:发布版本号,表示库的一些错误的修正,性能的改进等,并不需要添加任何新的接口,也不对接口进行更改。相同主版本号,次版本号的共享库,不同发布版本号之间完全兼容。是完全可以运行的。

5.SO-NAME

共享库的主版本号和次版本号决定了一个共享库的接口。程序中必须包含被依赖的共享库的名字和主版本号。由于历史原因,动态链接库和C语言的共享对象文件名规则不按Linux标准的共享库命名方法,但是C语言的SO-NAME是按照正常的规则。

实际上这个软链接会指向目录中主版本号相同的,次版本号和发布版本号最新的共享库。保证了所有的以SO—NAME 这样就保证了所有的以SO—NAME 为名的软链接都指向系统中最新的共享库。

一般这个软链接在的 dynamic 段的DT_NEED类型项中。

6.共享库的系统路径

目前大多数的Linux都遵循一项标准,FHS的标准,这个标准规定了一个系统中的系统文件如何存放

包括各个目录的组织,结构和作用。这个标准规定一个系统主要有三个存放共享库的位置。

Lib ,这个位置主要存放系统最关键和基础的共享库,比如动态链接器,C语言库运行库,数学库,这些库主要支持/bin/和/sbin 需要用到的库。

/usr/local/lib,这个位置放置了一些跟操作系统本身无关的库,主要是第三方应用程序的库,

/usr/lib,这个目录主要保存的是一些非系统运行时所需要的关键性的共享库。

7.共享库查找过程

动态链接的ELF 文件在启动时会同时启动动态链接器。程序所依赖的的模块路径保存在 dynamic

段里面,由DT_NEED类型的项表示,动态链接器对于模块的查找有一定的规则;如果DT_NEED里面保存的时绝对路径,那么动态链接器就会按照这个路径去查找;如果DT_NEED里面保存的是相对路径,那么动态链接器就会在/lib/,/usr/lib 和由/etc/ld.so.conf 配置文件指定的目录中查找共享库。为了程序的可以移植性和兼容性,共享库的路径往往是相对的。

两个环境变量:

LD_LIBRARY_PATH  这是一个由若干条路径组成的环境变量,每个环境变量由冒号隔开。默认情况下,这个路径为空,进程在启动的时候会首先查找共享库时,会首先查找由这个变量指定的路径。

例如我们想使用一个修改过的libc.so.6 可以将这个库放到/home/usr/下通过改变变量指向就可以达成改变链接指向的目的

$ LD_LIBRARY_PATH =  /home/user /bin/ls

也可以直接时用动态链接器

$ /lib/ld-linux.so.2 -library-path /home/user /bin/ls

动态链接器会按照下列顺序依次装载或查找共享对象

由环境变量LD_LIBRARY_PATH 指定的路径

由路径缓存文件/etc/ld.so.cache 指定的路径

默认共享库目录,先是/usr/lib 然后/lib

其实也可以使用GCC 的——L 参数

LD_PRELOAD

系统中另外还有一个环境变量叫做LD_PRELOAD,这个文件中我们可以指定预先加载的一些共享库或是目标文件。在这个文件里面指定的文件会在动态链接器按照固定规则搜索共享库之前装载,它比上一个路径里面锁指定的目录中的共享库还要优先。由于全局符号介入这个机制的存在,LD_PRELOAD里面指定的共享库或目标文件文件中的全局符号就会覆盖后面加载的同名全局符号,就可以使我们方便的改写标准C 库中的某几个函数或影响某几个其它函数。

另外还有一个有用的全局变量:LD_DEBUG

使用方法:

$LD_DEBUG = files ./helloword.out

直接在命令行使用就可以看到这个可执行文件的的装载整个过程。

Bindings  :  显示-动态链接与符号的全过程

files     :  显示装载过程

libs      :  显示共享库的查找过程

versions  :  显示符号的版本依赖关系

reloc     :  显示重定位的过程

symbols   :  显示符号表的查找的过程

statistics:  显示动态链接过程中的各种统计信息

all       :  显示以上的所有信息

help      :  显示上面的各种可选值的帮助信息

共享库的创建与安装:

创建共享库:

首先GCC 有一个参数-wl 参数这个参数可以将指定的参数传递给链接器

例如:

gcc -shared -fPIC -Wl,-soname,my_soname -o libray_name source_files

library_files

比如,我们拥有连各个C文件我们想把他们做成库文件。

两种方法:

gcc -shared -fPIC -Wl,-soname,libfoo.so.1 -o libfoo.so.1.0.0 libfoo1.c libfoo2.c

-lbar1 -lbar2

也可以分开制作:

gcc -c -g -Wall -o libfoo1.o libfoo1.c

gcc -c -g -Wall -o libfoo2.o libfoo1.c

ld -shared -soname libfoo.so.1 -o libfoo.so.1.0.0 libfoo1.o libfoo2.o -lbar1 -lbar2

几个注意事项:

不要把输出共享库中的符号和调试信息去掉,也不要使用gcc 的 -fomit-frame-pointer 选项

有时候如果需要调试程序但是又不希望影响现有的程序正常运行。使用LD_LIBRARY_PATH是一个很好的方法。一可以使用-rpath 这是链接器参数,GCC 参数(-Wl ,rpath)指定链接产生的目标程序的共享库查找路径

$ld -rapth /home/mylib -o program.out program.o -lsomelib

这样产生的输出可执行文件program.out 在被动态链接器装载时,动态链接器会首先在/home/mylib下查找动态库。

还有一个放止反向引用失败的参数 -Wl ,-export-dynamic

8.清除符号信息

正常情况下编译出来的共享库或者可执行文件里面带有符号信息和调试信息,这些信息在调试时非常有用,但是对于最终发布版本来说,这些符号信息用处并不大,并且使得文件尺寸边大。我们可以使用一个叫做strip 工具 。

$strip libfoo.so

也可以使用链接器的-S -s 两个参数,-S消除调试符号信息,-s消除所有符号信息,GCC 使用-Wl,-s

或者-Wl ,-S

9.共享库的安装

首先将库复制到某个标准的库目录中,然后使用ldconfig即可。

9.共享库构造函数与析构函数

很多时候我们希望在加载的时候能执行一些函数,其实只要在函数声明时加上__attribute__((constructor)) 的属性,就是指定该函数为共享库构造函数,这种函数就会在加载时执行,就是在main ( )函之前执行。如果打开共享库,就会在打开函数返回之前执行。

相对应的就是析构函数,同样也会私一个参数__attribute__((destoructor)),析构函数会在关闭共享库函数返回前执行完毕。

eg.void __attribute__((constructor)) add(int a ,int b)

当有多个函数的时候是有优先级之分的。

例如:

void __attribute__((constructor(5)) init_fun1(void)

数子5就是优先级。

对于构造函数来说,属性中优先级数子越小的函数将会在优先级大的函数之前执行,对于析构函数正好向反。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-17 20:19:07

共享库C/C++的相关文章

linux共享库

linux共享库 linux中共享库一般以.so.x.y.z 命名,其中x,y,z分别为主版本号.次版本号.发布版本号.同一个库,主版本号不同则相互不兼容:主版本相同,次版本号高的库比次版本号低的库有一些更新,增加了一些接口符号且保持原来的接口符号不变,但保持后向兼容:主版本号和次版本号相同,发布版本号不同,表示库的一些修改修正,不增加新功能. SO-NAME软链接 SO-NAME 软链接:共享库 libname.so.x.y.z 的SO-NAME软链接命名为 libname.so.x 即去掉次

linux C 动态共享库编译链接

  1.1.1         linux编写so文件的方式 1首先gcc编译的时候要加-fPIC选项,-fPIC是告诉gcc生成一个与位置无关的代码 2gcc链接的时候要加-shared选项,意思是生成一个so共享库. 对于linux或者unix,一个so文件,文件扩展名必须是so,文件名的前三个字母必须是lib 1.1.2         linux使用so gcc链接的时候需要加-L.代表从当前目录下找相关的so文件,-l文件名(但不包括文件名开头的lib和扩展名so) 例如编译一个mai

链接详解--共享库命名

按照共享库的命名惯例,每个共享库有三个文件名:real name,soname和linker name. soname是一个符号链接的名字,只包含共享库的主版本号,主版本号一致即可保证库函数的接口一致, 因此应用程序的.dynamic段只记录共享库的soname,只要soname一致,这个共享库就可以用. 使用共享库可以很方便地升级库文件而不需要重新编译应用程序,这是静态库没有的优点. 注:libc的版本号有一点特殊,libc-2.8.90.so的主版本号是6而不是2或2.8. linker n

windows动态链接库[DLL]与Linux共享库[SO]技术浅析

一.动态链接库的技术优点: 1)节省内存和磁盘空间:因为动态库在内存或磁盘中只需一份,便可供多个进程或程序使用. 2)模块化编程,方便协作:这一点静态库也能胜任. 3)使用动态加载DLL或SO时,便于模块升级,无需重新编译或链接整个程序. 二.windows的动态链接库: 1.windows的静态库生成的是.lib文件,其中包含了函数和数据实体,链接时合到程序中: 2.windows的动态库生成.dll文件并导出一个.lib文件,该.lib文件中的函数没有实体[不是一个 准确的说法],函数内部是

Linux共享库.so文件的命名和动态链接

Linux中的.so文件 是动态链接的产物 共享库理解为提供各种功能函数的集合,对外提供标准的接口 Linux中命名系统中共享库的规则 主版本号:不同的版本号之间不兼容 次版本号:增量升级 向后兼容 发行版本号:对应次版本的错误修正和性能提升,不影响兼容性 Linux中的共享库并不都是这样的格式 比如GLibc的共享库命名为:libc-x.y.z.so 动态链接器也是GLibc的一部分,使用ld-x.y.z.so命名 libm(数学库)等 SO-NAME机制 系统和程序中要链接的共享库的格式一般

android开发调用c++共享库so文件

1.编写libaab.cpp #include <stdio.h>#include <stdlib.h> #ifdef __cplusplusextern "C" {#endif int go() { return 555; } #ifdef __cplusplus}#endif 运行g++命令编译得到libaab.so arm-linux-androideabi-g++.exe -I/usr/local/linux-androideabi/platforms/

Linux学习笔记——例说makefile 增加系统共享库

0.前言 从学习C语言开始就慢慢开始接触makefile,查阅了很多的makefile的资料但总感觉没有真正掌握makefile,如果自己动手写一个makefile总觉得非常吃力.所以特意借助博客总结makefile的相关知识,通过例子说明makefile的具体用法. 例说makefile大致分为4个部分 1.只有单个C文件 2.含有多个C文件 3.需要包括头文件路径 4.增加宏定义 5.增加系统共享库 6.增加自定义共享库 7.一个实际的例子 [代码仓库]--makefile-example

axis2 webservice在websphere上需要设置was共享库

由于websphere自带的JAR包与axis2包冲突,要解决这个冲突,必须设置共享库. 在websphere控制台,找到环境>>>共享库,设置一个Cell类型的共享库,共享库名称为axis2,库包为: axis2-adb-1.5.6.jar axis2-kernel-1.5.6.jar axis2-transport-http-1.5.6.jar axis2-transport-local-1.5.6.jar axis2-jaxws-1.5.6.jar commons-fileuplo

Linux 共享库(动态库)

Linux 系统上有两类根本不同的 Linux 可执行程序.第一类是静态链接的可执行程序.静态可执行程序包含执行所需的所有函数 - 换句话说,它们是"完整的".因为这一原因,静态可执行程序不依赖任何外部库就可以运行. 第二类是动态链接的可执行程序. 静态可执行程序与动态可执行程序比较 我们可以用 ldd 命令来确定某一特定可执行程序是否为静态链接的: # ldd /sbin/sln not a dynamic executable "not a dynamic executa

c语言静态库与共享库的制作

/** * 此处的例子中所有的文件都在同一个目录下 * 若不在同一个路径下,请自行修改 **/ 静态库: 1> 编译源文件生成目标文件 gcc -c file1.c [file2.c ...]    //单文件注意文件名 2> 使用ar命令打包 ar -crv libxxx.a *.o        //库文件必须以lib开头,后缀为.a -c 创建 -v 显示过程 -r 插入文件 3> 使用静态库 方式一:将库文件当普通.o文件一样对待 gcc -o [execfilename] *.