Linux 系统,也同样面临和Window一样的问题,如何控制动态库的多个版本问题。Window之前没有处理好,为此专门有个名词来形容这个问题 “Dll hell”,其严重影响软件的升级和维护。 Dll hell 是指windows 上动态库新版本覆盖旧版本,但是却不兼容老版本。常常发生在程序升级之后,动态库更新,原有程序运行不起来;或者装新软件,但是已有的软件运行不起来。 同样Linux操作系统,也有同样的问题,那么它是怎么解决的呢?
创新互联2013年开创至今,是专业互联网技术服务公司,拥有项目成都网站设计、成都网站建设、外贸网站建设网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元北安做网站,已为上家服务,为北安各地企业和个人服务,联系电话:13518219792
Linux 为解决这个问题,引入了一套机制,如果遵守这个机制来做,就可以避免这个问题。 但是这只事一个约定,不是强制的。但是建议遵守这个约定,否则同样也会出现 Linux 版的Dll hell 问题。 下面来介绍一个这个机制。 这个机制是通过文件名,来控制dll (shared library) 的版本。
Linux 上的Dll ,叫shared library,其有三个名字,分别有不同的目的。
第一个是共享库本身的文件名(real name),其通常包含版本号,常常是是这样: libmath.so.1.1.1234 。 lib是Linux 上的库的约定前缀,math 是共享库名字,so 是共享库的后缀名,1.1.1234的是共享库的版本号,其主版本号+小版本号+build号。主版本号,代表当前动态库的版本,如果动态库的接口有变化,那么这个版本号就要加1;后面的两个版本号(小版本号 和 build 号)是告诉你详细的信息,比如为一个hot-fix 而生成的一个版本,其小版本号加1,build号也应有变化。 这个文件名包含共享库的代码。
第二个是动态库的soname( Short for shared object name),其是应用程序加载dll 时候,其寻找共享库用的文件名。其格式为
lib + math+.so + ( major version number)
其只包含major version number,换句话说,也就是只要其接口没有变,应用程序都可以用,不管你其后minor build version or build version。
问题来了,程序运行时怎么通过soname 找个real name? Soname 存在哪里?如果与real name 关联起来?什么时候存的?
这就是接下来要介绍的第三个共享库的名字,link name,顾名思义,就是在编译过程,link 阶段用的文件名。 其将sonmae 和real name 关联起来。
第三个名字,共享库的连接名(link name),是专门为build 阶段连接而用的名字。这个名字就是lib + math +.so ,比如libmath.so。其是不带任何版本信息的。在共享库编译过程中,连接(link) 阶段,编译器将生成一个共享库及real name,同时将共享库的soname,写在共享库文件里的文件头里面。可以用命令 readelf -d sharelibrary 去查看。
1、下载源码,解压缩sqlite-autoconf-3300100.tar.gz
2、进入解压目录,执行:
#:./configure --host=arm CC=arm-linux-gnueabi-gcc CXX=arm-linux-gnueabi-g++ --prefix=/usr
其中--host=要运行程序的主机
CC/CXX为用到的交叉编译工具链
--prefix=安装目录
3、make
将在当前文件目录下,自动生成可执行文件sqlite3及静态库文件sqlite3.a文件;
4、sudo make install
此命令会将可执行文件及静态库文件拷贝至安装目录中(也可手动拷贝)
5、以上步骤生成的可执行文件包含大量调试信息,文件比较大,可使用strip命令去掉其中的调试信息;
#:arm-linux-gnueabi-strip sqlite3
6、生成动态库文件:
arm-linux-gnueabi-gcc sqlite3.c -lpthread -ldl -fPIC -shared -o libsqlite3.so
交叉编译sqlite3,生成动态库
标签:ref gcc host pthread strip config 安装 目录 工具链
so文件是动态库的集合,由f90文件编译而成,此时f90程序中一般不包含program开头的主程序,而只包含module,例如:
将f90源文件编译为动态库时,使用命令
此时将生成两个文件,分别为bisectmod.mod和lib***.so,这儿的***是刚才自定义的名字,而*.mod文件名则是f90文件中module的名字,是自动生成的,如果一个f90文件中包含N个module,则会生成N个*.mod和1个lib***.so。so文件作为库文件,也可以由多个f90文件共同编译得到,相当于静态库中的打包,将多个库打包到一个里,如下:
动态库的使用包含两部分,一是在编译时,二是在程序运行时。
编译包含动态库的主程序时,要同时制定mod文件的路径和so文件的路径,如果mod文件、so文件以及主程序文件在同一目录下,直接指定so文件即可:
但是当使用第三方库时,通常会分别存放在include和lib文件夹中,此时就要单独指定路径了:
第一个参数-I是大写的i,代表include,第二个l是小写的L,代表lib的名字,可以省略lib以及后面的.so,第三个-L则是lib.so文件的路径。
这样编译的结果不能运行,因为运行时程序找不到lib***.so文件,最好的办法是指定LD_LIBRARY_PATH环境变量,当然也可以将lib***.so文件复制到系统的lib文件夹中。
Linux动态库的编译与使用 转载
Linux下的动态库以.so为后缀,我也是初次在Linux下使用动态库,写一点入门步骤,以便以后能方便使用。
第一步:编写Linux程序库
文件1.动态库接口文件
//动态库接口文件getmaxlen.h
#ifndef _GETMAXLEN_H_
#define _GETMAXLEN_H_
int getMaxLen(int *sel,int N);
#endif
文件2.动态库程序实现文件
//动态库程序实现文件getmaxlen.c
#include "getmaxlen.h"
int getMaxLen(int *sel,int N)
{
int n1=1,n2=1;
for(int i=1;iN;i++)
{
if(sel[i]sel[i-1])
{
n2 ++;
if(n2 n1)
{
n1 = n2;
}
}
else
{
n2 = 1;
}
}
return n1;
}
第二步:编译生成动态库
gcc getmaxlen.c –fPIC –shared –o libtest.so
由以上命令生成动态库libtest.so,为了不需要动态加载动态库,在命令时需以lib开头以.so为后缀。
–fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
–shared:指明编译成动态库。
第三步:使用动态库
1. 编译时使用动态库
文件1.动态库使用文件test.c
//使用动态库libtest.so,该文件名为test.c
#include "getmaxlen.h"
int main()
{
int Sel[] = {2,3,6,5,3,2,1,2,3,4,5,6,7,6,5};
int m;
m = getMaxLen(Sel,15);
printf("%d",m);
return 0;
}
编译命令:
gcc test.c –L . –l test –o test
–L:指明动态库所在的目录
-l:指明动态库的名称,该名称是处在头lib和后缀.so中的名称,如上动态库libtest.so的l参数为-l test。
测试:
ldd test
ldd 测试可执行文件所使用的动态库
2. 动态加载方式使用动态库
文件内容:
//动态库的动态加载使用
int main()
{
void *handle = NULL;
int (*getMaxLen)(int *sel,int N);
int sel[] = {1,2,5,4,5,8,6,5,9,5,4,5,4,1};
handle = dlopen("./libtest.so",RTLD_LAZY);
if(handle == NULL)
{
printf("dll loading error.\n");
return 0;
}
getMaxLen = (int(*)(int *,int))dlsym(handle,"getMaxLen");
if(dlerror()!=NULL)
{
printf("fun load error.\n");
return 0;
}
printf("%d\n",getMaxLen(sel,15));
}
编译命令:
gcc –ldl test1.c –o test
gcc -o test test.c ./libmytools.so