当前位置:必发365电子游戏 > 编程 >   可以动态链接的库
  可以动态链接的库
2019-12-19

动态链接,在可实施文件装载时或运转时,由操作系统的装载程序加载库。大多数操作系统将深入分析外界引用(比如库)作为加载进程的一片段。在这里些种类上,可试行文件包括多个叫做import   directory的表,该表的每黄金年代项包蕴三个库的名字。遵照表中记录的名字,装载程序在硬盘上查找供给的库,然后将其加载到内部存储器中预先不鲜明的职位,之后依据加载库后分明的库的地址更新可执路程序。可执路程序依据更新后的库消息调用库中的函数或征引库中的数据。那系列型的动态加载成为装载时加载   ,被归纳Windows和Linux的大繁多系统使用。装载程序在加载APP时要成功的最复杂的行事之风度翩翩就是加载时链接。  

   

  别的操作系统恐怕在运作时解析引用。在此些系统上,可执路程序调用操作系统API,将库的名字,函数在库中的编号和函数参数一起传递。操作系统肩负及时解析然后表示采用调用合适的函数。这种动态链接叫做运转时链接   。因为各种调用都会有系统开拓,运转时链接要慢得多,对利用的特性有消极的一面影响。今世操作系统已经超级少使用运转时链接。  

   

  能够动态链接的库,在Windows上是dynamic   link   library   (DLL卡塔尔国,在UNIX或Linux上是Shared   Library。库文件是优先编写翻译链接好的可推行文件,存款和储蓄在微处理机的硬盘上。大超多气象下,同一时候七个利用能够使用一个库的大同小异份拷贝,操作系统不须求加载那个库的四个实例。  

   

  Windows   和   Linux   的加载时链接是由操作系统来达成的,格式在不相同的种类下有差别的界别,但是原理仍旧同样的。

linux下文件的门类是不依靠于于其后缀名的,但日常来说:

.o,是目的文件,相当于windows中的.obj文件

.so 为分享库,是shared object,用于动态连接的,和dll大概

.a为静态库,是欲壑难填个.o合在协同,用于静态连接

.la为libtool自动生成的朝气蓬勃部分分享库,vi编辑查看,首要记录了一些布局音信。能够用如下命令查看*.la文件的格式   $file *.la

      *.la: ASCII English text

之所以能够用vi来查看其剧情。

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

创立.a库文件和.o库文件:

[yufei@localhost perl_c2]$ pwd

/home/yufei/perl_c2

[yufei@localhost perl_c2]$ cat mylib.c

#include <stdio.h>

#include <string.h>

void hello(){

        printf("success call from perl to c libraryn");

}

[yufei@localhost perl_c2]$ cat mylib.h

extern void hello();

[yufei@localhost perl_c2]$ gcc -c mylib.c

[yufei@localhost perl_c2]$ dir

mylib.c  mylib.h  mylib.o

[yufei@localhost perl_c2]$ ar -r mylib.a mylib.o

ar: 正在开创 mylib.a

[yufei@localhost perl_c2]$ dir

mylib.a  mylib.c  mylib.h  mylib.o

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

动态链接库*.so的编译与利用- -

                                      

动态库*.so在linux下用c和c++编制程序时平时会赶上,近期在网址找了几篇小说介绍动态库的编写翻译和链接,总算搞懂了那一个以前一向不太精晓得东东,这里做个笔记,也为别的正为动态库链接库而一点也不快的兄弟们提供一些增加帮衬。

1、动态库的编写翻译

上面通过三个例子来介绍如何生成叁个动态库。这里有二个头文件:so_test.h,三个.c文件:test_a.c、test_b.c、test_c.c,我们将那多少个公文编写翻译成三个动态库:libtest.so。

so_test.h:

#include <stdio.h>

#include <stdlib.h>

void test_a();

void test_b();

void test_必发365电子游戏官网,c();

test_a.c:

#include "so_test.h"

void test_a()

{

    printf("this is in test_a...n");

}

test_b.c:

#include "so_test.h"

void test_b()

{

    printf("this is in test_b...n");

}

test_c.c:

#include "so_test.h"

void test_c()

{

    printf("this is in test_c...n");

}

将那多少个文本编写翻译成叁个动态库:libtest.so

$ gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so

2、动态库的链接

在1、中,大家已经打响生成了四个要好的动态链接库libtest.so,上面大家因而一个主次来调用这一个库里的函数。程序的源文件为:test.c。

test.c:

#include "so_test.h"

int main()

{

    test_a();

    test_b();

    test_c();

    return 0;

}

l         将test.c与动态库libtest.so链接生成推行文书test:

$ gcc test.c -L. -ltest -o test

l         测量试验是或不是动态连接,即使列出libtest.so,那么相应是接连平时了

$ ldd test

l         实践test,能够看出它是何等调用动态库中的函数的。

3、编写翻译参数拆解剖判

最重大的是GCC命令行的一个采摘:

          -shared 该采用钦定生成动态连接库(让连接器生成T类型的导出符号表,不常候也生成弱连接W类型的导出符号),不用该标记外界程序无法连接。约等于三个可试行文件

l         -fPIC:表示编写翻译为地方独立的代码,不用此选项的话编译后的代码是岗位相关的之所以动态载入时是因而代码拷贝的点子来满意差别进度的急需,而不能够落得确实代码段分享的指标。

l         -L.:表示要延续的库在当前目录中

l         -ltest:编译器查找动态连接库时有隐含的命名准则,即在交付的名字前面加上lib,前面加上.so来显著库的名目

l         LD_LIBRARY_PATH:这么些情形变量提示动态连接器能够装载动态库的路径。

l         当然要是有root权限的话,能够改过/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来完毕同等的指标,不过只要未有root权限,那么只可以使用输出LD_LIBRARY_PATH的方法了。

4、注意

       调用动态库的时候有多少个难题会时时碰着,有的时候,明明已经将库的头文件所在目录 通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并钦定了“-l”的库名,但通过ldd命令察看时,就是安如磐石找不到你钦定链接的so文件,当时你要作的正是通过改良LD_LIBRARY_PATH恐怕/etc/ld.so.conf文件来内定动态库的目录。平日那样做就足以消除库不恐怕链接的标题了。

makefile里面怎么精确的编写翻译和连接生成.so库文件,然后又是在此外程序的makefile里面怎样编译和连接技艺调用那个库文件的函数????

答:

       你须求报告动态链接器、加载器ld.so在何地本事找到那几个分享库,能够设置境遇变量把库的不二等秘书籍增加到库目录/lib和/usr/lib,LD_LIBRARY_PATH=$(pwd卡塔尔,这种办法应用命令行方法不太低价,后生可畏种替代方式

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^注释^^^^^^^^^^^^^^^^^^^^^^^^^^^^

LD_LIBRARY_PATH可以在/etc/profile还是 ~/.profile还是 ./bash_profile里设置,或者.bashrc里,

改完后运转source /etc/profile或 . /etc/profile

更加好的法子是添入/etc/ld.so.conf, 然后试行 /sbin/ldconfig

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^注释^^^^^^^^^^^^^^^^^^^^^^^^^^^^

是把库路线增添到/etc/ld.so.conf,然后以root身份运营ldconfig

      也得以在一而再一连的时候钦定文件路线和名称 -I  -L.

      GCC=gcc

CFLAGS=-Wall -ggdb -fPIC

#CFLAGS=

all: libfunc test

libfunc:func.o func1.o

        $(GCC) -shared -Wl,-soname,libfunc.so.1 -o libfunc.so.1.1 $<

        ln -sf libfunc.so.1.1 libfunc.so.1

        ln -sf libfunc.so.1 libfunc.so

***********************************************注释************************************************

ln -s是用来成立软链接,也就也正是windows中的火速方式,在当前目录中创制上拔尖目录中的文件ttt的命名叫ttt2软链接的吩咐是ln -s ../ttt ttt2,假如原作件也正是ttt文件删除的话,ttt2也造成了空文件。

ln -d是用来创设硬链接,也就一定于windows中文件的别本,当原来的作品书删除的时候,并不影响“别本”的内容。

编写翻译目的文件时使用gcc的-fPIC选项,发生与义务无关的代码并能被加载到别的位置:

gcc –fPIC –g –c liberr.c –o liberr.o

使用gcc的-shared和-soname选项;

利用gcc的-Wl选项把参数字传送递给连接器ld;

应用gcc的-l选项突显的连年C库,以管教能够博得所需的启航(startup)代码,从而防止程序在行使不相同的,大概分歧盟版本的C库的类别上无法运行实践。

必发365网投 天天必发,gcc –g –shared –Wl,-soname,liberr.so –o liberr.so.1.0.0 liberr.o –lc

建构相应的灯号连接:

ln –s liberr.so.1.0.0 liberr.so.1;

ln –s liberr.so.1.0.0 liberr.so;

在MAKEFILE中:

$@

    表示准绳中的目的文件集。在情势准则中,假诺有四个对象,那么,"$@"正是相当于目的中形式定义的会见。

$%

    仅当对象是函数库文件中,表示法则中的指标成员名。举例,假若七个指标是"foo.a(bar.o卡塔尔(قطر‎",那么,"$%"正是"bar.o","$@"正是"foo.a"。假诺指标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。

$<

    注重指标中的第三个对象名字。假使借助指标是以形式(即"%")定义的,那么"$<"将是契合情势的生龙活虎雨后玉兰片的文本集。注意,其是叁个三个抽出来的。

$?

    全部比指标新的依附指标的成团。以空格分隔。

$^

    全部的信赖目的的集合。以空格分隔。纵然在依赖指标中有三个再度的,那么些这么些变量会去除重复的信任指标,只保留风姿罗曼蒂克份。

*********************************************注释***********************************************************************

test: test.o libfunc

        $(GCC) -o test test.o -L. -lfunc

%.o:%.c

        $(GCC) -c $(CFLAGS) -o $@ $<

clean:

        rm -fr *.o

        rm -fr *.so*

        rm -fr test

要生成.so文件,cc要带-shared 参数;要调用.so的文件,比方libfunc.so,能够在cc命令最终加上-lfunc,还要视情状拉长-L/usr/xxx 建议libfunc.so的不二法门;这样,在你要编写翻译的源文件中就足以调用libfunc.so那几个库文件的函数.

       前面包车型大巴都在说的基本上了,最终提示一下最佳提供八个接口头文件

       动态加载,用dlopen,dlclose,dlsym

 

ref:

  1. 介绍

  使用GNU的工具大家什么在Linux下开创协调的程序函数库?三个“程序 函数库”一句话来讲就是一个文件富含了某些编写翻译好的代码和数码,那一个编写翻译好的代码和多少能够在后头供其余的顺序行使。程序函数库能够使全部程序更为模块化,更易于重新编写翻译,而且更便利晋级。程序函数库可分为3种类型:静态函 数库(static libraries)、分享函数库(shared libraries)和动态加载函数库(dynamically loaded libraries)。

  静态函数库是在程序施行前就加盟到指标程序中去了;而分享函数库则是在前后相继运营的时候加载到程序中,它能够被 分歧的顺序共享;动态加载函数库则能够在程序运营的任几时候动态的加载。实际上,动态函数库并不是其它风流倜傥种库函数格式,差距是动态加载函数库是什么样被技士使用的。前边大家将举个例子表达。

  本文书档案主要参谋Program Library HOWTO,小编是luster(hwang@ustc.edu),任何非商业指标的再次发行本文档都以允许的,可是请保留我音信和本版权注明。本文书档案首先在www.linuxaid.com.cn宣布。

  2. 静态函数库

   静态函数库实际上便是轻便的叁个平日的对象文件的集纳,日常的话习于旧贯用“.a”作为文件的后缀。能够用ar这几个顺序来发生静态函数库文件。Ar 是archiver的缩写。静态函数库今后早已不在像以前用得那么多了,主假设分享函数库与之相相比有成都百货上千的优势的来由。慢慢地,大家都爱好使用分享函数 库了。可是,在大器晚成部分场子静态函数库仍旧在采纳,一来是保障一些与早前有些程序的同盟,二来它描述起来也比较轻便。

  静态库函数允许技士把程序link起来而不用重新编写翻译代码,节省了再也编写翻译代码的时日。可是,在后天这么快速的微型机前面,日常的程序的再度编写翻译也花销不了多少日子,所以 那一个优势已经不是像它原先那么鲜明了。静态函数库对开采者来说还是很有用的,比方你想把温馨提供的函数给别人使用,可是又想对函数的源代码进行保密,你就能够给人家提供一个静态函数库文件。理论上说,使用ELF格式的静态库函数生成的代码能够比使用分享函数库(恐怕动态函数 库)的程序运转速度上快一些,大约1-5%。

  成立三个静态函数库文件,或许往一个大器晚成度存在地静态函数库文件增加新的对象代码,可以用上面包车型客车指令:

ar rcs my_library.a file1.o file2.o

   这几个例子中是把对象代码file1.o和file2.o参加到my_library.a这几个函数库文件中,借使my_library.a空中楼阁则创制多少个新的文本。在用ar命令创制静态库函数的时候,还恐怕有其余部分能够采用的参数,能够到场ar的利用帮忙。这里不再赘述。

  风姿浪漫旦 你创建了一个静态函数库,你能够选拔它了。你能够把它作为你编写翻译和三番五次进程中的后生可畏局部用来生成你的可推行代码。倘使您用gcc来编写翻译发生可 推行代码的话,你可以用“-l”参数来钦点这几个库函数。你也能够用ld来做,使用它的“-l”和“-L”参数选项。具体用法,能够参见info:gcc。

 3. 分享函数库

  分享函数库中的函数是在当叁个可执路程序在开发银行的时候被加载。借使三个分享函数库不奇怪安装,全部的主次在重复运营的时候都能够自动加载最新的函数库中的函数。对于Linux系统还恐怕有越来越多的能够完结的成效:

o 进级了函数库但是依然允许程序行使老版本的函数库。 o 当试行有些特定程序的时候能够覆盖某些特定的库恐怕库中内定的函数。 o 能够在库函数被接纳的进程中改善那么些函数库。

  3.1. 有的预定

   若是你要编写的分享函数库帮忙全部有用的特色,你在编制的长河中必得固守一密密层层约定。你必须精晓库的两样的名字间的分别,举个例子它的 “soname”和“real name”之间的界别和它们是哪些相互影响的。你同样还要明白您应有把那个库函数放在你文件系统的怎么样地点等等。上面我们实际看看这么些主题素材。

  3.1.1. 分享库的命名

  每一种分享函数库都有个特别的名字,称作“soname”。Soname名字命名必需以“lib”作为前缀,然后是函数库的名字,然后是“.so”,最后是本子号信息。可是有个特例,正是特别底层的C库函数都不是以lib开端如此命名的。

  每一种分享函数库都有叁个当真的名字(“real name”),它是富含真正库函数代码的公文。真名有三个主版本号,和三个发行版本号。最终一个批发版本号是可选的,可以没有。主版本号和发行版本号令你能够清楚你到底是设置了哪些版本的库函数。

其余,还应该有二个名字是编写翻译器编写翻译的时候要求的函数库的名字,这几个名字正是简单的soname名字,而不含有别的版本号消息。

   管理分享函数库的根本是分别好这几个名字。当可执路程序必要在协和的次第中列出这个他们须要的分享库函数的时候,它风流倜傥旦用soname就能够了; 反过来,当您要创设三个新的分享函数库的时候,你要钦定二个一定的文书名,此中富含超级细节的版本消息。当你安装三个新本子的函数库的时候,你假若先将那几个函数库文件拷贝到一些一定的目录中,运转ldconfig这几个实用就足以。Ldconfig检查已经存在的库文件,然后创设soname的号子链接到实在 的函数库,相同的时候设置/etc/ld.so.cache那几个缓冲文件。那么些大家稍后再谈谈。

  Ldconfig并不设置链接的名字,平时的做法是在设置进程中成就这一个链接名字的建设构造,通常的话那个标识链接就差相当的少的对准最新的soname 也许最新版本的函数库文件。最棒把这一个符号链接指向soname,因为平常当您升官你的库函数的后,你就可以活动使用新本子的函数库勒。

  我们来比喻看看:

   /usr/lib/libreadline.so.3 是四个一心的豆蔻梢头体化的soname,ldconfig能够设置叁个符号链接到别的有些真正的函数库文件,举个例子是 /usr/lib/libreadline.so.3.0。同期还必得有八个链接名字,举例/usr/lib/libreadline.so 正是七个标识链接指向/usr/lib/libreadline.so.3。

3.1.2. 文件系统中等学园函授数库文件的岗位

   分享函数库文件必得放在一些特定的目录里,那样经过系统的景况变量设置,应用程序手艺科学的运用那一个函数库。超越50%的源码开拓的程序都根据GNU的一些规范,大家能够看info扶持文件获得信赖的证实,info音讯之处是:info: standards#Directory_Variables。GNU规范建议持有的函数库文件都放在/usr/local/lib目录下,並且提议命令 可执路程序都放在/usr/local/bin目录下。那都以一些习感觉常问题,能够改善的。

  文件系统档期的顺序化标准FHS(Filesystem Hierarchy 斯坦dard)( 下,可是即使某个库是在系统运维的时候要加载的,则停放/lib目录下,而那多少个不是系统本人生龙活虎部分的库则放到/usr/local/lib上面。

  上边三个渠道的不等并未实质的冲突。GNU提议的正统首要对于开垦者开荒源码的,而FHS的建议则是照准批发版本的门径的。具体的职责新闻方可看/etc/ld.so.conf里面的安顿新闻。

  3.2. 这个函数库怎么样使用

   在依靠GNU glibc的种类里,包含富有的linux系统,运行三个ELF格式的二进制可实施文件会自动运营和平运动转三个program loader。对于Linux系统,那些loader的名字是/lib/ld-linux.so.X(X是版本号)。这一个loader运转后,反过来就会load全部的其他本程序要使用的分享函数库。

  到底在怎么着目录里探寻分享函数库呢?那些概念缺省的是献身/etc/ld.so.conf文件之中,大家能够矫正这么些文件,参预大家和谐的部分 特殊的路线供给。大许多RedHat体系的批发包的/etc/ld.so.conf文件之中不包涵/usr/local/lib那几个目录,若无这几个目 录的话,大家得以纠正/etc/ld.so.conf,本人手动加上这几个条目。

  如果您想覆盖某些库中的一些函数,用本人的函数替换它们,同期保留该库中任何的函数的话,你可以在/etc/ld.so.preload中参与你想要替换的库(.o结尾的文本),这几个preloading的库函数将有优先加载的权利。

   当程序运营的时候寻觅全部的目录鲜明会效用十分低,于是Linux系统实际上用的是四个高效缓冲的做法。Ldconfig缺省气象下读出 /etc/ld.so.conf相关音讯,然后设置适本地符号链接,然后写二个cache到/etc/ld.so.cache这几个文件中,而这些/etc/ld.so.cache则足以被别的程序使得的使用了。那样的做法得以大大提升访问函数库的进度。那将必要每趟新增三个动态加载的函数库的时 候,就要运营ldconfig来更新那几个cache,假设要去除有些函数库,恐怕某些函数库的不二秘籍改革了,都要再一次运维ldconfig来更新这么些cache。经常的某个包微型机在装置八个新的函数库的时候就要运转ldconfig。

  其它,FreeBSD使用cache的文件不相像。FreeBSD的ELF cache是/var/run/ld-elf.so.hints,而a.out的cache责是/var/run/ld.so.hints。它们同样是由此ldconfig来更新。

  3.3. 情况变量

   五光十色的遭受变量调整着部分第生龙活虎的经过。举例你可以有的时候为您一定的主次的三遍实行钦命一个例外的函数库。Linux系统中,日常变量 LD_LIBRARY_PATH就是足以用来内定函数库查找路线的,并且这些门路平时是在寻找标准的路子早前查找。这么些是很有用的,非常是在调节和测量检验三个新的 函数库的时候,大概在非常规的场地使用一个肥标准的函数库的时候。情形变量LD_PRELOAD列出了颇负分享函数库中需求事情发生前加载的库文件,功用和 /etc/ld.so.preload相仿。那一个都以有/lib/ld-linux.so这一个loader来完成的。值得朝气蓬勃提的是, LD_LIBRARY_PATH能够在大部的UNIX-linke系统下正规起效用,可是绝不全体的种类下都能够应用,举例HP-UX系统下,就是用 SHLIB_PATH这一个变量,而在AIX下则运用LIBPATH那个变量。

  LD_LIBRARY_PATH在开采和调节和测验进度中一时大批量使用,可是不应该被叁个普通客户在装置进程中被安装程序改良,大家能够去参谋 变量。

  事实上还会有更加多的境遇变量影响着程序的调入进度,它们的名字常常正是以LD_或者RTLD_超越。大多数这一个情形变量的选用的文书档案都是不全,经常搞得人头昏目晕的,如若要确实弄通晓它们的用法,最棒去读loader的源码(也便是gcc的黄金时代局地)。

   允许顾客调整动态链接函数库将关乎到setuid/setgid那些函数要是极度规的功效供给的话。因而,GNU loader经常节制也许忽略客商对那一个变量使用setuid和setgid。假若loader通过判定程序的连带蒙受变量判定程序的是还是不是利用了 setuid可能setgid,倘诺uid和euid不相同,大概gid和egid部相符,那么loader就若是程序已经运用了setuid也许setgid,然后就大大的约束器调整那些老链接的权位。如若阅读GNU glibc的库函数源码,就能够驾驭地见到那或多或少,特别的大家能够看elf/rtld.c和sysdeps/generic/dl-sysdep.c这八个文本。那就表示假若你使得uid和gid与euid和egid分别相当于,然后调用一个前后相继,那么这几个变量就足以完全起效。

3.4. 开立两个分享函数库

   现在大家开头上学怎么着创建三个分享函数库。其实成立三个分享函数库特别轻松。首先创制object文件,那些文件将到场通过gcc –fPIC 参数命令参与到分享函数库里面。PIC的意思是“地方非亲非故代码”(Position Independent Code)。下边是两个专门的学问的格式:

gcc -shared -Wl,-soname,your_soname -o library_name file_list library_list

  上边再给三个例证,它创立八个object文件(a.o和b.o),然后创立多个暗含a.o和b.o的分享函数库。例子中”-g”和“-Wall”参数不是必须的。

gcc -fPIC -g -c -Wall a.cgcc -fPIC -g -c -Wall b.cgcc -shared -Wl,

-soname,liblusterstuff.so.1 -o liblusterstuff.so.1.0.1 a.o b.o -lc

  下边是有的急需在意之处:

· 不用接受-fomit-frame-pointer那一个编写翻译参数除非你只可以这么。就算采用了那几个参数得到的函数库照旧能够使用,可是那使得调试程序大致未有用,无法追踪调节和测验。 · 使用-fPIC来发生代码,并不是-fpic。 · 有些情状下,使用gcc 来生成object文件,供给选用“-Wl,-export-dynamic”这些选项参数。日常,动态函数库的符号表里面包蕴了这一个动态的靶子的标识。 这一个选项在开立ELF格式的文本时候,会将具备的暗号参预到动态符号表中。能够参见ld的援救获得更详尽的求证。

  3.5. 装置和接纳分享函数库

  大器晚成旦您了贰个分享函数库,你还要求设置它。其实轻松的格局正是拷贝你的库文件到钦命的正规的目录(比如/usr/lib),然后运行ldconfig。

   假诺您未有权限去做这件业务,举例你不可能改改/usr/lib目录,那么您就必须要通过改善你的意况变量来落到实处那些函数库的应用了。首先,你需求创设那几个分享函数库;然后,设置有些必得需符号链接,极其是从soname到真正的函数库文件的标识链接,轻易的方式就是运作ldconfig:

ldconfig -n directory_with_shared_libraries

  然后你就能够安装你的LD_LIBRARY_PATH那么些意况变量,它是三个以逗号分隔的门路的集聚,那一个能够用来指明分享函数库的搜寻路线。举例,使用bash,就足以这么来运营叁个前后相继my_program:

LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH my_program

   即使你要求的是重载部分函数,则你就须求创制七个分包必要重载的函数的object文件,然后设置LD_PRELOAD情形变量。日常你能够很 方便的进级你的函数库,借使有个别API改换了,创制库的程序会改动soname。不过,如若三个函数进级了有个别函数库而保持了原本的soname,你可以强行将老版本的函数库拷贝到某些地点,然后重新命名那一个文件(举例利用原来的名字,然后前边加.orig后缀),然后创造三个小的“wrapper”脚本 来安装这一个库函数和相关的东西。举个例子上边包车型地铁例子:

#!/bin/sh export LD_LIBRARY_PATH=/usr/local/my_lib:$LD_LIBRARY_PATH exec

/usr/bin/my_program.orig $*

  大家得以由此运行ldd来看有个别程序行使的分享函数库。比如你能够看ls这一个实用工具使用的函数库:

ldd /bin/ls

    libtermcap.so.2 => /lib/libtermcap.so.2 (0x4001c000)

    libc.so.6 => /lib/libc.so.6 (0x40020000)

    /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

  经常小编么能够观望三个soname的列表,蕴含路径。在装有的意况下,你都最少能够见到八个库:

· /lib/ld-linux.so.N(N是1恐怕更加大,日常最少2)。

那是以此奋力加载其余全部的分享库的库。

· libc.so.N(N应该大于大概等于6卡塔尔(قطر‎。那是C语言函数库。

   值得风流浪漫提的是,不要在对你不信的程序运维ldd命令。在ldd的manual里面写得很驾驭,ldd是因而设置某个特殊的情状变量(举个例子,对 于ELF对象,设置LD_TRACE_LOADED_OBJECTS),然后运转这些顺序。那样就有超大希望使得某地程序可能使得ldd来进行某个意料之外的 代码,而发生不安全的隐患。

3.6. 不相配的函数库

  如若几个新版的函数库要和老版本的二进制的库不相称,则soname须求改造。对于C语言,风姿洒脱共有4个主导的说辞使得它们在二进制代码上很难宽容:

  o. 一个函数的编写更换了,那样它就大概与最早始的概念不相相符。

  o. 输出的多少项改成了。

  o. 某个输出的函数删除了。

  o. 有些输出函数的接口改变了。

  假设您能幸免那一个地点,你就足以保持您的函数库在二进制代码上的合作,或许说,你能够使得你的次序的行使二进制接口(ABI:Application Binary Interface)上异常。

  4. 动态加载的函数库Dynamically Loaded (DL卡塔尔(英语:State of Qatar) Libraries

   动态加载的函数库Dynamically loaded (DL卡塔尔(قطر‎libraries是大器晚成类函数库,它能够在程序运维进度中的任曾几何时刻加载。它们特别相符在函数中加载一些模块和plugin扩充模块的场所,因为它能够在 当程序需求有些plugin模块时才动态的加载。比方,Pluggable Authentication Modules(PAM卡塔尔系统便是用动态加载函数库来驱动助理馆员能够配备和重新配献身份验证音信。

  Linux系统下,DL函数库与别的函数库在格式上尚无新鲜的界别,我们前面提到过,它们创造的时候是专门的学业的object格式。首要的分化就是这么些函数库不是在程序链接的时候依然运营的时候加载,而是通过三个API来开垦多少个函数库,寻觅符号表,管理错误和关闭函数库。平时C语言情形下,须求包含这些头文件。

  Linux中使用的函数和Solaris中千篇大器晚成律,都是dlpoen() API。那时候不是两全的平台都应用雷同的接口,比如HP-UX使用shl_load(卡塔尔国机制,而Windows平台用别的的其余的调用接口。假诺您的目的是使得你的代码有很强的移植性,你应当利用一些wrapping函数库,那样的wrapping函数库遮盖分裂的阳台的接口差距。生龙活虎种方法是应用 glibc函数库中的对动态加载模块的支撑,它采用部分神秘的动态加载函数库分界面使得它们得以夸平台使用。具体能够参照他事他说加以考察http: //developer.gnome.org/doc/API/glib/glib-dynamic-loading-of-modules.html. 此外贰个措施是采取libltdl,是GNUlibtool的一片段,能够更进一层参考CORBA相关质地。

  4.1. dlopen()

  dlopen函数展开一个函数库然后为后面包车型客车选择做筹算。C语言原形是:

void * dlopen(const char *filename, int flag);

  如若文件名filename是以“/”带头,也正是应用相对路线,那么dlopne就直接运用它,而不去探索有些意况变量大概系统设置的函数库所在的目录了。不然dlopen()

  就能够遵从上边包车型大巴次第查找函数库文件:

  1. 条件变量LD_LIBRA陆风X8Y指明的路线。 2. /etc/ld.so.cache中的函数库列表。 3. /lib目录,然后/usr/lib。然则有的很老的a.out的loader则是运用相反的程序,也正是先查/usr/lib,然后是/lib。

   Dlopen(卡塔尔(英语:State of Qatar)函数中,参数flag的值必须是RTLD_LAZY或者RTLD_NOW,RTLD_LAZY的野趣是resolve undefined symbols as code from the dynamic library is executed,而RTLD_NOW的意思是resolve all undefined symbols before dlopen() returns and fail if this cannot be done'。

  借使有有些个函数库,它们中间有点依附关系的话,举例X信任Y,那么你就要先加载那么些被依赖的函数。比方先加载Y,然后加载X。

  dlopen()函数的重回值是二个句柄,然后后边的函数就经过利用那一个句柄来做进一层的操作。借使张开失利dlopen(卡塔尔(قطر‎就重返二个NULL。假使贰个函数库被频繁开荒,它会回去同样的句柄。

  假诺三个函数Curry面有一个出口的函数名称为_init,那么_init就能够在dlopen()那个函数重临前被实践。大家能够动用这几个函数在自家的函数库里面做一些开首化的行事。大家后边会连续钻探这一个题指标。

  4.2. dlerror()

  通过调用dlerror(卡塔尔(قطر‎函数,大家得以得到最终一遍调用dlopen(卡塔尔(قطر‎,dlsym(卡塔尔国,大概dlclose()的错误消息。

4.3. dlsym()

  假如你加载了多个DL函数库而不去行使当然是不恐怕的了,使用一个DL函数库的最器重的三个函数正是dlsym(卡塔尔(英语:State of Qatar),那个函数在叁个早已展开的函数Curry面查找给定的符号。那几个函数如下概念:

void * dlsym(void *handle, char *symbol);

  函数中的参数handle正是由dlopen打开后归来的句柄,symbol是贰个以NIL结尾的字符串。

   如果dlsym(卡塔尔(英语:State of Qatar)函数未有找到供给搜求的symbol,则赶回NULL。假使您掌握有个别symbol的值不容许是NULL恐怕0,那么就很 好,你就足以依赖那一个再次来到结果判别查找的symbol是不是留存了;然则,假若有些symbol的值就是NULL,那么这么些论断就有标题了。标准的判别方式是先调用dlerror(卡塔尔国,清除以前或然存在的大错特错,然后调用dlsym()来走访三个symbol,然后再调用dlerror()来判别是还是不是出现了错 误。贰个数一数二的进程如下:

dlerror();

s = (actual_type) dlsym(handle, symbol_being_searched_for);

if ((err = dlerror()) != NULL)

{

}

else

{

}

  4.4. dlclose()

   dlopen(卡塔尔(英语:State of Qatar)函数的反进程正是dlclose()函数,dlclose()函数用力关闭二个DL函数库。Dl函数库维持三个能源选用的计数器,当调用dlclose的时候,就把那几个计数器的计数减风姿罗曼蒂克,假使流速计为0,则实在的放出掉。真正自由的时候,假诺函数Curry面有_fini(卡塔尔国这一个函 数,则自动调用_fini()这些函数,做一些需要的拍卖。Dlclose()重返0表示成功,别的非0值表示错误。

  4.5. DL Library Example

  上面是二个事例。例子中调入math函数库,然后打字与印刷2.0的余弦函数值。例子中年老年是都检查是不是出错。应该是个正确的表率:

  #include

  #include

  #include

  int main(int argc, char **argv)

  {

    void *handle;

    double (*cosine)(double);

    char *error;

    handle = dlopen ("/lib/libm.so.6", RTLD_LAZY);

    if (!handle) {

        fputs (dlerror(), stderr);

        exit(1);

    }

    cosine = dlsym(handle, "cos");

    if ((error = dlerror()) != NULL)

  {

        fputs(error, stderr);

        exit(1);

    }

    printf ("%f ", (*cosine)(2.0));

    dlclose(handle);

}

  假如那个顺序名字叫foo.c,那么用下边包车型大巴指令来编写翻译:

  gcc -o foo foo.c -ldl

  1. 其他

  5.1. nm命令

   nm命令能够列出叁个函数库文件中的符号表。它对于静态的函数库和分享的函数库都起效率。对于三个加以的函数库,nm命令能够列出函数库中定义 的装有符号,满含各样符号的值和项目。还能提交在原程序中那一个函数(符号)是在有一点点行定义的,然则这一定必要编写翻译该函数库的时候加“-l”选项。

   关于符号的等级次序,这里大家再多研讨一下。符号的体系是以二个字母的款型体现的,小写字母表示那么些符号是本地(local)的,而大写字母则象征 这么些符号是大局的(global,externel)。日常的话,类型有弹指间二种:T、D、B、U、W。各自的意义如下:T表示在代码段中定义的平常变量 符号;D表示时起始化过的数据段;B表示最初化的数据段;U表示从未定义的,在此个Curry面使用了,但是在其他库中定义的号子;W,weak的缩写,表示借使其余函数库中也可以有对那些符号的概念,则别的标记的定义能够覆盖这一个概念。

  假如您知道一个函数的名字,可是你不掌握这一个函数在什么样库中定义的,那么能够用mn的“-o”选项和grep命令来查找库的名字。-o选项使得展现的每大器晚成行皆有这些函数库文件名。例如,你要找出“cos”这一个是在哪些地点定义的,差不离能够用下边包车型大巴下令:

nm -o /lib*  可以动态链接的库。 /usr/local/libGROUP ( /lib/libc.so.6

/usr/lib/libc_nonshared.a )

  更加多的消息方可参照texinfo文书档案中关于ld链接的台本部分。日常的新闻还能参见: info:ld#Options 和info:ld#Commands,也能够参见info:ld#Option Commands。

  5.4. GNU libtool

   倘若您正在编写翻译的种类相很有利的移植到其余操作系统下,你能够利用GNUlibtool来创设和设置那些函数库。GNUlibtool是叁个函数库帮忙的超人的剧本。Libtool隐蔽了使用多个可移植的函数库的负担性。Libtool提供了三个足以移植的分界面来创造object文件,链接函数库(静态或然分享的),何况安装那个库。它还隐含了libltdl,三个可移植的动态函数库调入程序的wrapper。越来越多的 详细商讨,可以在

  5.5. 剔除一些标记

  在贰个生育的文本湖北中国广播企业余大学符号皆认为着debug而含有的,占用了许多上空。假使空间远远不足,并且那些标识或者不再需求,就足以将内部一些剔除。

   最棒的不二等秘书诀就是先平时的改造你供给的object文件,然后debug和测验你须要的蓬蓬勃勃对东西。风华正茂旦您一点一滴测量检验甘休了,就能够用strip去删 除一些没有须要的号子了。Strip命令能够使您很方便的垄断(monopoly卡塔尔(قطر‎删除什么符号,而保留什么符号。Strip的切实用法能够参见其扶持文件。

  此外的情势正是选拔GNU ld的选项“-S”和“-s”;“-S”会删除一些debugger的符号,而“-s”则是将享有的号子新闻都剔除。平日大家能够在gcc中加那样的参数“-Wl,-S”和“-Wl,-s”来达到这一个目标。

摘要

下边是大器晚成对例证,例子中我们会利用二种函数库(静态的、分享的和动态加载的函数库)。文件libhello.c是二个函数库,libhello.h 是它的头文件;demo_use.c则是三个行使了libhello函数库的。Script_static和script_dynamic分别演示怎么样以 静态和分享艺术使用函数库,而前面包车型地铁demo_dynamic.c和script_dynamic则象征演示怎样以动态加载函数库的章程来接纳它。

(2002-08-25 17:38:37)

By Wing

  6. 愈来愈多的事例

   下边是局地事例,例子中咱们会使用三种函数库(静态的、分享的和动态加载的函数库)。文件libhello.c是三个函数库, libhello.h是它的头文件;demo_use.c则是叁个施用了libhello函数库的。Script_static和 script_dynamic分别演示如何以静态和分享艺术利用函数库,而前边的demo_dynamic.c和script_dynamic则表示演示 怎么着以动态加载函数库的措施来使用它。

  6.1. File libhello.c

#include

void hello(void)

{

printf("Hello, library world.

");

}

  6.2. File libhello.h

void hello(void);

  6.3. File demo_use.c

#include "libhello.h"

int main(void)

{

hello();

return 0;

}

  6.4. File script_static

#!/bin/sh

# Static library demo

# Create static library's object file, libhello-static.o.

# I'm using the name libhello-static to clearly

# differentiate the static library from the

# dynamic library examples, but you don't need to use

# "-static" in the names of your

# object files or static libraries.gcc -Wall -g -c -o libhello-static.o

libhello.c

# Create static library.ar rcs libhello-static.a libhello-static.o

# At this point we could just copy libhello-static.a

# somewhere else to use it.

# For demo purposes, we'll just keep the library

# in the current directory.

# Compile demo_use program file.gcc -Wall -g -c demo_use.c -o demo_use.o

# Create demo_use program; -L. causes "." to be searched during

# creation of the program. Note that this command causes

# the relevant object file in libhello-static.a to be

# incorporated into file demo_use_static.gcc -g -o demo_use_static

demo_use.o -L. -lhello-static

# Execute the program../demo_use_static

  6.5. File script_shared

#!/bin/sh

# Shared library demo

# Create shared library's object file, libhello.o.gcc -fPIC -Wall

-g -c libhello.c

# Create shared library.

# Use -lc to link it against C library, since libhello

# depends on the C library.gcc -g -shared -Wl,-soname,libhello.so.0 -o

libhello.so.0.0 libhello.o -lc# At this point we could just copy

libhello.so.0.0 into

# some directory, say /usr/local/lib.

# Now we need to call ldconfig to fix up the symbolic links.

# Set up the soname. We could just execute:

# ln -sf libhello.so.0.0 libhello.so.0

# but let's let ldconfig figure it out./sbin/ldconfig -n .

# Set up the linker name.

# In a more sophisticated setting, we'd need to make

# sure that if there was an existing linker name,

# and if so, check if it should stay or not.ln -sf libhello.so.0

libhello.so

# Compile demo_use program file.gcc -Wall -g -c demo_use.c -o

demo_use.o

# Create program demo_use.

# The -L. causes "." to be searched during creation

# of the program; note that this does NOT mean that "."

# will be searched when the program is executed.gcc -g -o demo_use

demo_use.o -L. -lhello

# Execute the program. Note that we need to tell the program

# where the shared library is,

using LD_LIBRARY_PATH.LD_LIBRARY_PATH="." ./demo_use

  6.6. File demo_dynamic.c

#include

#include

#include

typedef void (*simple_demo_function)(void);

int main(void)

{

const char *error;

void *module;

simple_demo_function demo_function;

module = dlopen("libhello.so", RTLD_LAZY);

if (!module)

{

  fprintf(stderr, "Couldn't open libhello.so: %s

",dlerror());

  exit(1);

}

dlerror();

demo_function = dlsym(module, "hello");

if ((error = dlerror()))

{

  fprintf(stderr, "Couldn't find hello: %s

", error);

  exit(1);

}

(*demo_function)();

dlclose(module);

return 0;

}

  6.7. File script_dynamic

#!/bin/sh

# Dynamically loaded library demo

# Presume that libhello.so and friends have

# been created (see dynamic example).

# Compile demo_dynamic program file into an object file.gcc

-Wall -g -c demo_dynamic.c

# Create program demo_use.

# Note that we don't have to tell it where to search

for DL libraries,

# since the only special library this program uses won't be

# loaded until after the program starts up.

# However, we DO need the option -ldl to include the library

# that loads the DL libraries.gcc -g -o demo_dynamic

demo_dynamic.o -ldl

# Execute the program. Note that we need to tell the

# program where get the dynamically loaded library,

# using LD_LIBRARY_PATH.LD_LIBRARY_PATH="." ./demo_dynamic

 

转