精华内容
下载资源
问答
  • 静态库和动态库

    2021-05-17 13:27:57
    1.什么是库库lib是编译好的二进制代码,可以被操作系统载入内存执行,一般是预先编译好的函数的集合,可以通过头文件链接到库文件,执行已经编译好的代码段。库一般分为静态库(static lib,在linux系统一般是.a文件)...

    1.什么是库

    库lib是编译好的二进制代码,可以被操作系统载入内存执行,一般是预先编译好的函数的集合,可以通过头文件链接到库文件,执行已经编译好的代码段。

    库一般分为静态库(static lib,在linux系统一般是.a文件)和动态库(dynamic lib,也叫共享库,在linux系统一般是.so文件)。二者的不同点在于被载入的时间不同:

    静态库.a在编译的过程中会被编译到可执行文件,也就是说会增大可执行文件的体积。

    动态库则是在执行的过程中才会去读取.so文件,不用编译进可执行程序,因此可执行程序体积较小。缺点是拷贝代码时如果没有.so文件可能会造成无法执行。‘

    2.静态库

    静态库

    程序在编译阶段会把静态库的内容复制到目标文件中,在链接阶段将引用的静态库打包到可执行文件中。因此称为静态链接。这里可以发现,静态链接将静态库直接打包进入可执行文件,那么他的组织形式一定和.o文件类似。

    实际上,一个静态库是一组目标文件的集合(.o),很多目标文件被打包成一个文件,并且直接参与链接。

    静态库有以下特点:

    1.静态库对函数的链接是在编译时完成的

    2.程序在运行时不再需要静态库,因为对应的程序段已经被复制到原来的位置,移植方便。

    3.可执行文件占用空间较大,因为静态库内容被复制进入了可执行文件编译结果。

    创建静态库

    linux静态库的创建命名规则:lib[library_name].a,lib为前缀,中间是库名,.a为扩展名。

    创建静态库

    现在有如下代码,一定要把头文件和函数体分开声明,否则使用静态库的时候没有头文件只能猜了哦。

    **

    * @file: unite_time.h

    * @author: mattbaisteins@gmail.com

    * @date: 2020-08-03

    * @brif:

    **/

    #ifndef _UNITE_TIME_H

    #define _UNITE_TIME_H

    #include #include #include #include #include #define BUFFER_SIZE 4096

    /*

    * get time yymmdd, eg. 190803

    * @param void

    * @return string now_time

    */

    std::string get_time();

    #endif // end _UNITE_TIME_H

    /**

    * @file: unite_time.cpp

    * @author: mattbaisteins@gmail.com

    * @date: 2020-08-03

    * @brif:

    **/

    #include "unite_time.h"

    #include std::string get_time() {

    time_t raw_time;

    struct std::tm *time_info;

    char buffer[BUFFER_SIZE];

    std::time(&raw_time);

    time_info = std::localtime(&raw_time);

    std::strftime(buffer, sizeof(buffer) - 1, "%y%m%d", time_info);

    return std::string(buffer);

    }

    1.首先把代码先编译成目标文件.o(unite_time.o)

    gcc -c unite_time.cpp

    2 使用ar工具将目标文件打包成静态库.a文件(libunite_time.a)

    ar -crv libunite_time.a unite_time.o

    注:ar的用法如下

    (1)ar是什么

    ar命令可以用来创建、修改库,也可以从库中提出单个模块。库是一单独的文件,里面包含了按照特定的结构组织起来的其它的一些文件(称做此库文件的member)。原始文件的内容、模式、时间戳、属主、组等属性都保留在库文件中。

    ar命令格式:ar [-] {dmpqrtx} [abcfilNoPsSuvV] [membername] [count] archive files…

    例如我们可以用ar rv libtest.a hello.o hello1.o来生成一个库,库名字是test,链接时可以用-ltest链接。该库中存放了两个模块hello.o和hello1.o。选项前可以有‘-'字符,也可以没有。下面我们来看看命令的操作选项和任选项。现在我们把{dmpqrtx}部分称为操作选项,而[abcfilNoPsSuvV]部分称为任选项。

    【注:ar可让您集合许多文件,成为单一的备存文件。在备存文件中,所有成员文件皆保有原来的属性与权限】

    2)参数介绍 指令参数

    -d  删除库文件中的成员文件。

    -m  变更成员文件在库文件中的次序。

    -p  显示库文件中的成员文件内容。

    -q  将问家附加在库文件末端。

    -r  将文件插入库文件中。

    -t  显示库文件中所包含的文件。

    -x  自库文件中取出成员文件。

    选项参数

    a  将文件插入库文件中指定的成员文件之后。

    b  将文件插入库文件中指定的成员文件之前。

    c  建立库文件。

    f  为避免过长的文件名不兼容于其他系统的ar指令指令,因此可利用此参数,截掉要放入库文件中过长的成员文件名称。

    i  将问家插入库文件中指定的成员文件之前。

    o  保留库文件中文件的日期。

    s  若库文件中包含了对象模式,可利用此参数建立备存文件的符号表。

    S  不产生符号表。

    u  只将日期较新文件插入库文件中。

    v  程序执行时显示详细的信息。

    V  显示版本信息。

    ar用来管理一种文档。这种文档中可以包含多个其他任意类别的文件。这些被包含的文件叫做这个文档的成员。ar用来向这种文档中添加、删除、解出成员。成员的原有属性(权限、属主、日期等)不会丢失。实际上通常只有在开发中的目标连接库是这种格式的,所以尽管不是,我们基本可以认为ar是用来操作这种目标链接库(.a文件)的。

    (3)ar的常用用法

    创建库文件

    我不知道怎么创建一个空的库文件。好在这个功能好像不是很需要。通常人们使用“ar cru liba.a a.o"这样的命令来创建一个库并把a.o添加进去。"c"关键字告诉ar需要创建一个新库文件,如果没有指定这个标志则ar会创建一个文件,同时会给出 一个提示信息,"u"用来告诉ar如果a.o比库中的同名成员要新,则用新的a.o替换原来的。但是我发现这个参数也是可有可无的,可能是不同版本的ar 行为不一样吧。实际上用"ar -r liba.a a.o"在freebsd5上面始终可以成功。

    加入新成员

    使用"ar -r liba.a b.o"即可以将b.o加入到liba.a中。默认的加入方式为append,即加在库的末尾。“r"关键字可以有三个修饰符"a”, “b"和"i”。 "a"表示after,即将新成员加在指定成员之后。例如"ar -ra a.c liba.a b.c"表示将b.c加入liba.a并放在已有成员a.c之后; “b"表示before,即将新成员加在指定成员之前。例如"ar -rb a.c liba.a b.c”; "i"表示insert,跟"b"作用相同。

    列出库中已有成员

    “ar -t liba.a"即可。如果加上"v"修饰符则会一并列出成员的日期等属性。

    删除库中成员

    “ar -d liba.a a.c"表示从库中删除a.c成员。如果库中没有这个成员ar也不会给出提示。如果需要列出被删除的成员或者成员不存在的信息,就加上"v"修饰符。

    从库中解出成员

    “ar -x liba.a b.c”

    调整库中成员的顺序

    使用"m"关键字。与"r"关键字一样,它也有3个修饰符"a”,“b”, “i”。如果要将b.c移动到a.c之前,则使用"ar -mb a.c liba.a b.c”

    使用用静态库

    1 #include 2 #include 3 #include "unite_time.h"

    4

    5 int main() {

    6 std::cout << "test static lib" << std::endl;

    7 std::cout << get_time() << std::endl;

    8 return 0;

    9

    10 }

    Linux下使用静态库,只需要在编译的时候,指定静态库的搜索路径(-L选项)、指定静态库名(不需要lib前缀和.a后缀,-l选项)。

    g++ test.cpp -L./ -lunite_time -o test

    就可以生成可执行文件test啦,,我们执行可执行文件test,可以看到test 二进制包大小是24k,成功生成了libunite_time.a

    ad166957d4b73d7bf74bfd290a00c4b4.png

    3.动态库

    动态库

    动态库,动态库是在程序运行时被载入引用。 只在程序中做一个标记,当用到被标记的库中的函数时,程序会顺着做的标记找到库,然后调用需要的函数,并不会像静态库一样将库中的所有内容都复制包含进来。

    为什么有了静态库还要设计动态库?

    首先是空间浪费是静态库的一个问题。我们可以这样想假如某一个人静态库占用1M内存,此时有2000个这样的程序需要用到这个库,那么此时,每个程序都需要将这个静态库中的内容拷贝一份到自己里面,这样内存中就会产生多分库函数,并且这些会占用将近2GB的空间。

    另外一个问题是由于静态库对程序的更新、部署和发布带来的麻烦。假如某一个静态库更新了,所有使用它的应用程序都需要重新编译、发布给用户(对于玩家来说,只是一个小小的改动,但是却会导致整个程序重新下载,全量更新)

    因此我们需要引入动态库,由于动态库是程序运行时被载入的,不同的程序如果调用相同的库,在内存中里只需要有一份该库的实例,避免了空间的浪费,同时也解决了静态库对程序的更新、部署和发布带来的麻烦,用户只需要更新动态库即可,增量更新。

    动态库特点总结:

    (1)动态库把对一些库函数的链接载入推迟到程序运行的时期。

    (2)可以实现进程之间的资源共享。(因此动态库也称为共享库)

    (3)将一些程序升级变得简单。

    (4)甚至可以真正做到链接载入完全由程序员在程序代码中控制(显式调用)。

    ## 创建动态库

    1.linux动态库的命名规则

    动态链接库的名字形式为 libxxx.so,前缀是 lib,后缀名为“.so”;针对于实际库文件,每个共享库都有个特殊的名字“so name”。在程序启动后,程序通过这个名字来告诉动态加载器,该载入哪个共享库;在文件系统中,soname仅是一个链接到实际动态库的链接。对于动态库而言,每个库实际上都有另一个名字给编译器来用。它是一个指向实际库镜像文件的链接文件(lib+soname+.so)。

    2.创建动态库(.so)

    同样是上面的代码

    第一步:生成位置无关的目标文件.o(unite_time.o),此时要加编译器选项-fpic

    g++ -fPIC -c unite_time.cpp //-fPIC 创建与地址无关的编译程序(pic,position independent code),是为了能够在多个应用程序间共享。

    第二步:生成动态库,此时要加链接器选项-shared

    g++ -shared -o libunite_time.so unite_time.o

    也可以将上面两步合为一步

    g++ -fPIC -shared -o libunite_time.so unite_time.cpp

    使用动态库

    g++ test.cpp -L./ -lunite_time -o test

    8a487a60ae8e12f265ab965b5c2889ba.png

    Linux系统在同一目录下有可能找不到动态库位置,那么在执行程序时如何定位动态库的位置呢?

    (1) 当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径。此时就需要系统动态载入器(dynamic linker/loader)。

    (2)对于elf格式的可执行程序,是由ld-linux.so*来完成的,它先后搜索elf文件的 DT_RPATH段—环境变LD_LIBRARY_PATH—/etc/ld.so.cache文件列表—/lib/,/usr/lib 目录找到库文件后将其载入内存。

    如何让系统能够找到它?

    (1)如果安装在/lib或者/usr/lib下,那么ld默认能够找到,无需其它操作。

    (2)如果安装在其它目录,需要将其添加到/etc/ld.so.cache文件中,步骤如下:

    第一步:编辑/etc/ld.so.conf文件,加入库文件所在目录的路径

    第二步:运行ldconfig ,该命令会重建/etc/ld.so.cache文件

    4使用动态库运行时加载的特性做热更新

    根据动态库运行时加载的特性,我们可以在不重新编译可执行文件的情况下,对动态库进行热更新,使得test执行过程中执行热热加载

    我们修改一下库函数的内容

    /**

    * @file: unite_time.cpp

    * @author: mattbaisteins@gmail.com

    * @date: 2020-08-03

    * @brif:

    **/

    #include "unite_time.h"

    #include std::string get_time() {

    return "hello world";

    }

    重新生成动态库,不重新编译可执行文件,可以发现结果已经变成了新的动态库内容

    09eba72ceccf82d1997acd7bed1549c4.png

    热加载

    展开全文
  • 在《下 动态链接的创建与应用》一文中,我介绍了LINUX动态链接的基本知识.其要点是:用户根据实际情况需要,利用 dlopen,dlsym,dlclose等动态链接操作函数,装入指定的动态链接中指定的函数,然后加以执行.程序中...

    在《下 动态链接库的创建与应用》一文中,我介绍了LINUX动态链接库的基本知识.其要点是:用户根据实际情况需要,利用 dlopen,dlsym,dlclose等动态链接库操作函数,装入指定的动态链接库中指定的函数,然后加以执行.程序中使用很少的动态函数时,这样的 做法尚可.如果程序需要调用大量的动态函数,那么采用这样的编程手段将是非常繁复的,所以我们必须使用一种更为聪明的办法,以减少代码量,提高工作效率. 这就是现在我要举例介绍的《LINUX动态链接库高级应用》. 注:本文举的例子类似上篇文章,只是文件的内容已做相应修改,裁减了不少.示例程序ady.c和两个动态函数的源程序getdate.c与gettime.c仅修改了头文件的名字,其内容不再列出.本文使用头文件为adatetime.h.

    要想高效地应用LINUX动态链接库(尤其是用户自己编写的),需要做以下工作:  一、编写合格的动态链接库头文件  C语言的头文件,可供一个或多个程序引用,里面一般定义程序所需的常量,自定义类型及函数原型说明等.其中的函数原型说明,则供编译器检查语法,用于排除引用参数时类型不一致的错误.只有编写合格的动态链接库头文件,程序员才能正确使用动态链接库内的函数.

    动态链接库头文件要采用C语言标准格式,其中的动态函数原型定义,不必象上文介绍的那样用(*动态函数名)的描述形式.请看下面的例子:(每行开始的数字为所在行行号,为笔者添加,供注解使用)

    1 /* adatetime.h : 纵横软件制作中心雨亦奇()编写, 2002-03-06. */ 2  3 #ifndef __DATETIME_H 4  5 #define __DATETIME_H 6  7 /* 日期结构 */ 8 typedef struct 9 { 10 int year; 11 int mon; 12 int day; 13 }DATETYPE; 14  15 /* 时间结构 */ 16 typedef struct 17 { 18 char hour; 19 char min; 20 char sec; 21 }TIMETYPE; 22  23 int getdate(DATETYPE *d); /* 取当前日期 */ 24 int gettime(TIMETYPE *t); /* 取当前时间 */ 25  26 #endif 27

    注:与上文的datetime.h文件比较,从该头文件第23,24行可以看到,动态函数getdate,gettime的原型定义改变了,不再使用(*getdate),(*gettime)的格式了(这种格式使用较为罗嗦).

    二、正确编译与命名动态链接库

    为了让GCC编译器生成动态链接库,编译时须加选项-shared.(这点须牢记)

    LINUX系统中,为了让动态链接库能被系统中其它程序共享,其名字应符合“lib*.so*”这种格式.如果某个动态链接库不符合此格式,则LINUX的动态链接库自动装入程序(ld.so)将搜索不到此链接库,其它程序也无法共享之.

    格式中,第一个*通常表示为简写的库名,第二个*通常表示为该库的版本号.如:在我的系统中,基本C动态链接库的名字为 libc.so.6,线程 pthread动态链接库的名字为libpthread.so.0等等.本文例子所生成的动态链接库的名字为libmy.so,虽没有版本号,但也符合所 要求的格式.

    生成该动态链接库的维护文件makefile-lib内容如下:

    1 # makefile : 纵横软件制作中心雨亦奇编写, 2002-03-07. 2  3 all : libmy.so 4  5 SRC = getdate.c gettime.c 6  7 TGT = $(SRC:.c=.o) 8  9 $(SRC) : adatetime.h 10 @touch $@ 11  12 %.o : %.c 13 cc -c $? 14  15 # 动态链接库(libmy.so)生成 16 libmy.so : $(TGT) 17 cc -s -shared -o $@ $(TGT) 18

    运行命令:

    $ make -f makefile-lib $

    即生成libmy.so库.

    注: 维护文件中,第17行用-shared选项以生成动态链接库,用-s选项以去掉目标文件中的符号表,从而减小文件长度.

    三、共享动态链接库

    3.1 动态链接库配置文件

    为了让动态链接库为系统所使用,需要维护动态链接库的配置文件--/etc/ld.so.conf.此文件内,存放着可被LINUX共享 的动态链接库所在目录的名字(系统目录/lib,/usr/lib除外),各个目录名间以空白字符(空格,换行等)或冒号或逗号分隔.一般的LINUX发 行版中,此文件均含一个共享目录/usr/X11R6/lib,为X window窗口系统的动态链接库所在的目录.

    下面看看我的系统中此文件的内容如何:

    # cat /etc/ld.so.conf /usr/X11R6/lib /usr/zzz/lib #

    由上可以看出,该动态库配置文件中,增加了一个/usr/zzz/lib目录.这是我自己新建的共享库目录,下面存放我新开发的可供系统共享的动态链接库.

    3.2 动态链接库管理命令

    为了让动态链接库为系统所共享,还需运行动态链接库的管理命令--ldconfig.此执行程序存放在/sbin目录下.

    ldconfig命令的用途,主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内 所列的目录下,搜索出可共享的动态链接库(格式如前介绍,lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件.缓存文件默认 为 /etc/ld.so.cache,此文件保存已排好序的动态链接库名字列表.

    ldconfig通常在系统启动时运行,而当用户安装了一个新的动态链接库时,就需要手工运行这个命令.

    ldconfig命令行用法如下:

    ldconfig [-v|--verbose] [-n] [-N] [-X] [-f CONF] [-C CACHE] [-r ROOT] [-l] [-p|--print-cache] [-c FORMAT] [--format=FORMAT] [-V] [-?|--help|--usage] path...

    ldconfig可用的选项说明如下:

    (1) -v或--verbose : 用此选项时,ldconfig将显示正在扫描的目录及搜索到的动态链接库,还有它所创建的连接的名字.

    (2) -n : 用此选项时,ldconfig仅扫描命令行指定的目录,不扫描默认目录(/lib,/usr/lib),也不扫描配置文件/etc/ld.so.conf所列的目录.

    (3) -N : 此选项指示ldconfig不重建缓存文件(/etc/ld.so.cache).若未用-X选项,ldconfig照常更新文件的连接.

    (4) -X : 此选项指示ldconfig不更新文件的连接.若未用-N选项,则缓存文件正常更新.

    (5) -f CONF : 此选项指定动态链接库的配置文件为CONF,系统默认为/etc/ld.so.conf.

    (6) -C CACHE : 此选项指定生成的缓存文件为CACHE,系统默认的是/etc/ld.so.cache,此文件存放已排好序的可共享的动态链接库的列表.

    (7) -r ROOT : 此选项改变应用程序的根目录为ROOT(是调用chroot函数实现的).选择此项时,系统默认的配置文件/etc/ld.so.conf,实际对应的为 ROOT/etc/ld.so.conf.如用-r /usr/zzz时,打开配置文件/etc/ld.so.conf时,实际打开的是/usr/zzz/etc/ld.so.conf文件.用此选项,可以 大大增加动态链接库管理的灵活性.

    (8) -l : 通常情况下,ldconfig搜索动态链接库时将自动建立动态链接库的连接.选择此项时,将进入专家模式,需要手工设置连接.一般用户不用此项.

    (9) -p或--print-cache : 此选项指示ldconfig打印出当前缓存文件所保存的所有共享库的名字.

    (10) -c FORMAT 或 --format=FORMAT : 此选项用于指定缓存文件所使用的格式,共有三种:old(老格式),new(新格式)和compat(兼容格式,此为默认格式).

    (11) -V : 此选项打印出ldconfig的版本信息,而后退出.

    (12) -? 或 --help 或 --usage : 这三个选项作用相同,都是让ldconfig打印出其帮助信息,而后退出.

    举三个例子:

    例1:

    # ldconfig -p 793 libs found in cache `/etc/ld.so.cache' libzvt.so.2 (libc6) => /usr/lib/libzvt.so.2 libzvt.so (libc6) => /usr/lib/libzvt.so libz.so.1.1.3 (libc6) => /usr/lib/libz.so.1.1.3 libz.so.1 (libc6) => /lib/libz.so.1 ...... #

    注: 有时候用户想知道系统中有哪些动态链接库,或者想知道系统中有没有某个动态链接库,这时,可用-p选项让ldconfig输出缓存文件中的动态链接库列 表,从而查询得到.例子中,ldconfig命令的输出结果第1行表明在缓存文件/etc/ld.so.cache中找到793个共享库,第2行开始便是 一系列共享库的名字及其全名(绝对路径).因为实际输出结果太多,为节省篇幅,以......表示省略的部分.

    例2:

    # ldconfig -v /lib: liby.so.1 -> liby.so.1 libnss_wins.so -> libnss_wins.so ...... /usr/lib: libjscript.so.2 -> libjscript.so.2.0.0 libkspell.so.2 -> libkspell.so.2.0.0 ...... /usr/X11R6/lib: libmej-0.8.10.so -> libmej-0.8.10.so libXaw3d.so.7 -> libXaw3d.so.7.0 ...... #

    注: ldconfig命令在运行正常的情况下,默认不输出什么东西.本例中用了-v选项,以使ldconfig在运行时输出正在扫描的目录及搜索到的共享库, 用户可以清楚地看到运行的结果.执行结束后,ldconfig将刷新缓存文件/etc/ld.so.cache.

    例3:

    # ldconfig /usr/zhsoft/lib #

    注: 当用户在某个目录下面创建或拷贝了一个动态链接库,若想使其被系统共享,可以执行一下"ldconfig 目录名"这个命令.此命令的功能在于让ldconfig将指定目录下的动态链接库被系统共享起来,意即:在缓存文件/etc/ld.so.cache中追 加进指定目录下的共享库.本例让系统共享了/usr/zhsoft/lib目录下的动态链接库.需要说明的是,如果此目录不在/lib,/usr/lib 及/etc/ld.so.conf文件所列的目录里面,则再度运行ldconfig时,此目录下的动态链接库可能不被系统共享了.

    3.3 动态链接库如何共享 了解了以上知识,我们可以采用以下三种方法来共享动态链接库:(注:均须在超级用户状态下操作,以我的动态链接库libmy.so共享过程为例)

    (1)拷贝动态链接库到系统共享目录下,或在系统共享目录下为该动态链接库建立个连接(硬连接或符号连接均可,常用符号连接).这里说的 系统共享目录,指的是LINUX动态链接库存放的目录,它包含/lib,/usr/lib以及/etc/ld.so.conf文件内所列的一系列目录.

    # cp libmy.so /lib # ldconfig #

    或:

    # ln -s `pwd`/libmy.so /lib # ldconfig #

    (2)将动态链接库所在目录名追加到动态链接库配置文件/etc/ld.so.conf中.

    # pwd >> /etc/ld.so.conf # ldconfig #

    (3)利用动态链接库管理命令ldconfig,强制其搜索指定目录,并更新缓存文件,便于动态装入.

    # ldconfig `pwd` #

    需要说明的是,这种操作方法虽然有效,但效果是暂时的,供程序测试还可以,一旦再度运行ldconfig,则缓存文件内容可能改变,所需 的动态链接库可能不被系统共享了.与之相比较,前两种方法是可靠的方法,值得业已定型的动态链接库共享时采用.前两种方法还有一个特点,即最后一条命令都 是 ldconfig,也即均需要更新一下缓存文件,以确保动态链接库的共享生效.

    四、含有动态函数的程序的编译

    4.1 防止编译因未指定动态链接库而出错

    当一个程序使用动态函数时,编译该程序时就必须指定含所用动态函数的动态链接库,否则编译将会出错退出.如本文示例程序ady.c的编译(未明确引用动态链接库libmy.so):

    # cc -o ady ady.c /tmp/ccL4FsJp.o: In function `main': /tmp/ccL4FsJp.o(.text+0x43): undefined reference to `gettime' collect2: ld returned 1 exit status #

    注: 因为ady.c所含的动态函数getdate,gettime不在系统函数库中,所以连接时出错.

    4.2 编译时引用动态链接库的几种方式

    (1)当所用的动态链接库在系统目录(/lib,/usr/lib)下时,可用编译选项-l来引用.即:

    # cc -lmy -o ady ady.c #

    注:编译时用-l选项引用动态链接库时,库名须使用其缩写形式.本例的my,表示引用libmy.so库.若引用光标库libncurses.so,须用-lncurses.注意,-l选项与参数之间不能有空格,否则会出错.

    (2)当所用的动态链接库在系统目录(/lib,/usr/lib)以外的目录时,须用编译选项-L来指定动态链接库所在的目录(供编译器查找用),同时用-l选项指定缩写的动态链接库名.即:

    # cc -L/usr/zzz/lib -lmy -o ady ady.c #

    (3)直接引用所需的动态链接库.即:

    # cc -o ady ady.c libmy.so #

    # cc -o ady ady.c /lib/libmy.so #

    等等.其中,动态链接库的库名可以采用相对路径形式(文件名不以/开头),也可采用绝对路径形式(文件名以/开头).

    五、动态链接程序的运行与检查

    5.1 运行

    编译连接好含动态函数的程序后,就可以运行它了.动态链接程序因为共享了系统中的动态链接库,所以其空间占用很小.但这并不意味功能的减少,它的执行与静态连接的程序执行,效果完全相同.在命令提示符下键入程序名及相关参数后回车即可,如下例:

    $ ady 动态链接库高级应用示范 当前日期: 2002-03-11 当前时间: 19:39:06 $

    5.2 检查

    检查什么?检查动态链接程序究竟需要哪些共享库,系统中是否已有这些库,没有的话,用户好想办法把这些库装上.

    怎么检查呢?这里,告诉你一个实用程序--ldd,这个程序就是专门用来检查动态链接程序依赖哪些共享库的.

    ldd命令行用法如下:

    ldd [--version] [-v|--verbose] [-d|--data-relocs] [-r|--function-relocs] [--help] FILE...

    各选项说明如下:

    (1) --version : 此选项用于打印出ldd的版本号.

    (2) -v 或 --verbose : 此选项指示ldd输出关于所依赖的动态链接库的尽可能详细的信息.

    (3) -d 或 --data-relocs : 此选项执行重定位,并且显示不存在的函数.

    (4) -r 或 --function-relocs : 此选项执行数据对象与函数的重定位,同时报告不存在的对象.

    (5) --help : 此选项用于打印出ldd的帮助信息.

    注: 上述选项中,常用-v(或--verbose)选项.

    ldd的命令行参数为FILE...,即一个或多个文件名(动态链接程序或动态链接库).

    例1:

    $ ldd ady libmy.so => ./libmy.so (0x40026000) libc.so.6 => /lib/libc.so.6 (0x40028000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) $

    注: 每行=>前面的,为动态链接程序所需的动态链接库的名字,而=>后面的,则是运行时系统实际调用的动态链接库的名字,所需的动态链接库在系统 中不存在时,=>后面将显示"not found",括号所括的数字为虚拟的执行地址.本例列出ady所需的三个动态链接库,其中libmy.so为自己新建的动态链接库,而 libc.so.6与/lib/ld-linux.so.2均为系统的动态链接库,前一个为基本C库,后一个动态装入库(用于动态链接库的装入及运行).

    例2:

    $ ldd -v ady libmy.so => ./libmy.so (0x40026000) libc.so.6 => /lib/libc.so.6 (0x40028000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

    Version information: ./ady: libc.so.6 (GLIBC_2.1.3) => /lib/libc.so.6 libc.so.6 (GLIBC_2.0) => /lib/libc.so.6 ./libmy.so: libc.so.6 (GLIBC_2.1.3) => /lib/libc.so.6 libc.so.6 (GLIBC_2.0) => /lib/libc.so.6 /lib/libc.so.6: ld-linux.so.2 (GLIBC_2.1.1) => /lib/ld-linux.so.2 ld-linux.so.2 (GLIBC_2.2.3) => /lib/ld-linux.so.2 ld-linux.so.2 (GLIBC_2.1) => /lib/ld-linux.so.2 ld-linux.so.2 (GLIBC_2.2) => /lib/ld-linux.so.2 ld-linux.so.2 (GLIBC_2.0) => /lib/ld-linux.so.2 $

    注:本例用-v选项以显示尽可能多的信息,所以例中除列出ady所需要的动态链接库外,还列出了程序所需动态链接库版本方面的信息.

    小结: 在LINUX动态链接库的高级应用中,关键有两点,一是如何让动态链接库为LINUX系统所共享,二是编译连接程序时如何做.让动态链接库为系统所共享, 主要是用ldconfig管理命令,维护好系统共享库的缓存文件/etc/ld.so.cache.编译连接时如何做?注意连接上所用的动态链接库就可以 了.LINUX动态链接库的高级应用,用一用就明白:其实,就是这么简单!

    展开全文
  • 大家都知道,在 WINDOWS 系统中有很多的动态链接(以.DLL为后缀的文件,DLL即Dynamic Link Library),大家都知道,在WINDOWS系统中有很多的动态链接(以.DLL为后缀的文件,DLL即Dynamic Link Library)。这种动态...

    大家都知道,在 WINDOWS 系统中有很多的动态链接库(以.DLL为后缀的文件,DLL即Dynamic Link Library),

    大家都知道,在WINDOWS系统中有很多的动态链接库(以.DLL为后缀的文件,DLL即Dynamic Link Library)。这种动态链接库,和静态函数库不同,它里面的函数并不是执行程序本身的一部分,而是根据执行程序需要按需装入,同时其执行代码可在多个执行程序间共享,节省了空间,提高了效率,具备很高的灵活性,得到越来越多程序员和用户的青睐。那么,在LINUX系统中有无这样的函数库呢?

    答案是肯定的,LINUX的动态链接库不仅有,而且为数不少。在/lib目录下,就有许多以.so作后缀的文件,这就是LINUX系统应用的动态链接库,只不过与WINDOWS叫法不同,它叫so,即Shared Object,共享对象。(在LINUX下,静态函数库是以.a作后缀的) X-WINDOW作为LINUX下的标准图形窗口界面,它本身就采用了很多的动态链接库(在/usr/X11R6/lib目录下),以方便程序间的共享,节省占用空间。著名的APACHE网页服务器,也采用了动态链接库,以便扩充程序功能。你只需将PHP动态链接库拷到其共享目录,修改一下配置,APACHE就可以支持PHP网页了。如果你愿意,可以自己编写动态链接库,让APACHE支持你自己定义的网页格式。这就是动态链接的好处。

    1、LINUX下动态链接库的创建

    在LINUX系统下,创建动态链接库是件再简单不过的事情。只要在编译函数库源程序时加上-shared选项即可,这样所生成的执行程序即为动态链接库。从某种意义上来说,动态链接库也是一种执行程序。按一般规则,程序名应带.so后缀。下面举个例子说说。

    我准备编写两个函数,一个用于查询当前日期getdate,一个用于查询当前时间gettime,并将这两个函数存于动态链接库my.so中。为此,需要做以下几项工作。

    1.1 编写用户接口文件datetime.h,内容如下(每行前面的数字为行号):

    ----------------------------------------------------------------------

    1 /* datetime.h : 纵横软件制作中心雨亦奇编写, 2001-06-28. */

    2

    3 #ifndef __DATETIME_H

    4

    5 #define __DATETIME_H

    6

    7 /* 日期结构 */

    8 typedef struct

    9 {

    10 int year;

    11 int mon;

    12 int day;

    13 }DATETYPE;

    14

    15 /* 时间结构 */

    16 typedef struct

    17 {

    18 char hour;

    19 char min;

    20 char sec;

    21 }TIMETYPE;

    22

    23 /* 函数原型说明 */

    24

    25 #ifdef SHARED

    26 int (*getdate)(DATETYPE *d);

    27 #else

    28 int getdate(DATETYPE *d);

    29 #endif

    30

    31 #ifdef SHARED

    32 int (*gettime)(TIMETYPE *t);

    33 #else

    34 int gettime(TIMETYPE *t);

    35 #endif

    36

    37 #endif

    38

    ----------------------------------------------------------------------

    这个用户接口文件中,先定义了日期与时间结构,接着定义一下函数的原型。动态函数与静态函数的原型说明不同的是,动态函数应使用(*函数名)的形式,以便引用其指针。若要引用文件中的动态函数说明,用户应该定义一下SHARED宏,这样才能使用。

    1.2 编写getdate.c,源程序如下:

    ----------------------------------------------------------------------

    1 /* getdate.c : 纵横软件制作中心雨亦奇编写, 2001-06-28. */

    2

    3 #include "time.h"

    4 #include "datetime.h"

    5

    6 int getdate(DATETYPE *d)

    7 {

    8 long ti;

    9 struct tm *tm;

    10

    11 time(&ti);

    12 tm=localtime(&ti);

    13 d->year=tm->tm_year+1900;

    14 d->mon=tm->tm_mon+1;

    15 d->day=tm->tm_mday;

    16 }

    17

    ----------------------------------------------------------------------

    在getdate函数中,先调用time取得以秒计的系统时间,再用localtime函数转换一下时间结构,最后调整得到正确的日期。

    1.3 编写gettime.c,源程序如下:

    ----------------------------------------------------------------------

    1 /* gettime.c : 纵横软件制作中心雨亦奇编写, 2001-06-28. */

    2

    3 #include "time.h"

    4 #include "datetime.h"

    5

    6 int gettime(TIMETYPE *t)

    7 {

    8 long ti;

    9 struct tm *tm;

    10

    11 time(&ti);

    12 tm=localtime(&ti);

    13 t->hour=tm->tm_hour;

    14 t->min=tm->tm_min;

    15 t->sec=tm->tm_sec;

    16 }

    17

    ----------------------------------------------------------------------

    gettime函数与getdate函数相仿,先用time函数取得以秒计的系统时间,再用localtime函数转换一下时间结构,最后返回当前的时间(不需调整)。

    1.4 编写维护文件makefile-lib,内容如下:

    ----------------------------------------------------------------------

    1 # makefile-lib : 纵横软件制作中心雨亦奇编写, 2001-06-28.

    2

    3 all : my.so

    4

    5 SRC = getdate.c gettime.c

    6

    7 TGT = $(SRC:.c=.o)

    8

    9 $(SRC) : datetime.h

    10 @touch $@

    11

    12 %.o : %.c

    13 cc -c $?

    14

    15 # 动态函数库(my.so)生成

    16 my.so : $(TGT)

    17 cc -shared -o $@ $(TGT)

    18

    ----------------------------------------------------------------------

    编写维护文件的目的,在于方便程序员维护程序,尤其是维护比较大的工程项目。一个素质良好的程序员应该学会熟练地编写维护文件makefile。定义了文件间的依赖关系后,一旦源文件发生变化,仅需make一下,其目标文件维护代码会自动执行,从而自动更新目标文件,减少了许多工作量。注意: 每行维护代码必须以TAB(跳格键)开始,不是的话make时将出错。

    本维护文件第1行是注释行,以#号开头;文件第3行定义所有需要维护的函数库;第5行定义相关源程序文件;第7行定义目标文件;第9-10行说明所有源程序依赖于datetime.h头文件,并有相应维护代码,即touch一下,更新一下源文件的时间;第12-13行定义.o文件依赖于相应的.c文件,并指定了维护代码,即用cc编译一下;第16-17行定义共享库my.so依赖的目标文件,维护代码中用-shared编译选项,以生成动态链接库my.so。

    1.5 运行make -f makefile-lib 命令

    make运行后,动态链接库my.so就产生了,我们就可以在程序中调用了。如果想让系统所有用户都可以使用,则应以root用户登录系统,将这个库拷贝到/lib目录下(命令:cp my.so /lib),或者在/lib目录下建个符号连接即可(命令:ln -s `pwd`/my.so /lib)。

    2、LINUX下动态链接库的使用

    2.1 重要的dlfcn.h头文件

    LINUX下使用动态链接库,源程序需要包含dlfcn.h头文件,此文件定义了调用动态链接库的函数的原型。下面详细说明一下这些函数。

    2.1.1 dlerror

    原型为: const char *dlerror(void);

    当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功,LINUX系统中动态链接库的创建与使用Windows系统》(https://www.unjs.com)。

    2.1.2 dlopen

    原型为: void *dlopen (const char *filename, int flag);

    dlopen用于打开指定名字(filename)的动态链接库,并返回操作句柄。

    filename: 如果名字不以/开头,则非绝对路径名,将按下列先后顺序查找该文件。

    (1) 用户环境变量中的LD_LIBRARY值;

    (2) 动态链接缓冲文件/etc/ld.so.cache

    (3) 目录/lib,/usr/lib

    flag表示在什么时候解决未定义的符号(调用)。取值有两个:

    1) RTLD_LAZY : 表明在动态链接库的函数代码执行时解决。

    2) RTLD_NOW : 表明在dlopen返回前就解决所有未定义的符号,一旦未解决,dlopen将返回错误。

    dlopen调用失败时,将返回NULL值,否则返回的是操作句柄。

    2.1.3 dlsym : 取函数执行地址

    原型为: void *dlsym(void *handle, char *symbol);

    dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。由此地址,可以带参数执行相应的函数。

    如程序代码: void (*add)(int x,int y); /* 说明一下要调用的动态函数add */

    add=dlsym("xxx.so","add"); /* 打开xxx.so共享库,取add函数地址 */

    add(89,369); /* 带两个参数89和369调用add函数 */

    2.1.4 dlclose : 关闭动态链接库

    原型为: int dlclose (void *handle);

    dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。

    2.2 在程序中使用动态链接库函数

    2.2.1 程序范例

    下面的程序装载了动态链接库my.so,并用getdate,gettime取得当前日期与时间后输出。

    ----------------------------------------------------------------------

    1 /************************************/

    2 /* 文件名称: dy.c */

    3 /* 功能描述: 动态链接库应用示范程序 */

    4 /* 程序编写: 纵横软件制作中心雨亦奇 */

    5 /* 编写时间: 2001-06-28 */

    6 /************************************/

    7

    8 #include "stdio.h" /* 包含标准输入输出文件 */

    9

    10 #include "dlfcn.h" /* 包含动态链接功能接口文件 */

    11 #define SOFILE "./my.so" /* 指定动态链接库名称 */

    12

    13 #define SHARED /* 定义宏,确认共享,以便引用动态函数 */

    14 #include "datetime.h" /* 包含用户接口文件 */

    15

    16 main()

    17 {

    18 DATETYPE d;

    19 TIMETYPE t;

    20 void *dp;

    21 char *error;

    22

    23 puts("动态链接库应用示范");

    24

    25 dp=dlopen(SOFILE,RTLD_LAZY); /* 打开动态链接库 */

    26

    27 if (dp==NULL) /* 若打开失败则退出 */

    28 {

    29 fputs(dlerror(),stderr);

    30 exit(1);

    31 }

    32

    33 getdate=dlsym(dp,"getdate"); /* 定位取日期函数 */

    34

    35 error=dlerror(); /* 检测错误 */

    36 if (error) /* 若出错则退出 */

    37 {

    38 fputs(error,stderr);

    39 exit(1);

    40 }

    41

    42 getdate(&d); /* 调用此共享函数 */

    43 printf("当前日期: %04d-%02d-%02d\n",d.year,d.mon,d.day);

    44

    45 gettime=dlsym(dp,"gettime"); /* 定位取时间函数 */

    46

    47 error=dlerror(); /* 检测错误 */

    48 if (error) /* 若出错则退出 */

    49 {

    50 fputs(error,stderr);

    51 exit(1);

    52 }

    53

    54 gettime(&t); /* 调用此共享函数 */

    55 printf("当前时间: %02d:%02d:%02d\n",t.hour,t.min,t.sec);

    56

    57 dlclose(dp); /* 关闭共享库 */

    58

    59 exit(0); /* 成功返回 */

    60

    61 }

    ----------------------------------------------------------------------

    程序说明:

    第8行: 包含标准输入输出头文件,因为程序中使用了printf,puts,fputs等标准输入输出函数,需要让编译器根据头文件中函数的原型,检查一下语法;

    第10-11行: 包含动态链接库功能头文件,并定义动态链接库名称;

    第13-14行: 定义宏SHARED以便引用14行的头文件datetime.h中的动态函数说明;

    第25行: 用dlopen打开SOFILE共享库,返回句柄dp;

    第27-31行: 检测dp是否为空,为空则显示错误后退出;

    第33行: 用dlsym取得getdate函数动态地址;

    第35-40行: 如果dlerror返回值不为空,则dlsym执行出错,程序显示错误后退出;

    第42-43行: 执行getdate调用,输出当前日期;

    第45行: 用dlsym取得gettime函数动态地址;

    第47-52行: 如果dlerror返回值不为空,则dlsym执行出错,程序显示错误后退出;

    第54-55行: 执行gettime调用,输出当前时间;

    第57行: 用dlclose关闭dp所指示的动态链接库;

    第59行: 程序退出,返回0值。

    2.2.2 编写维护文件

    维护文件makefile内容如下:

    ----------------------------------------------------------------------

    1 # makefile : 纵横软件制作中心雨亦奇编写, 2001-06-28.

    2

    3 all : dy

    4

    5 DYSRC = dy.c

    6

    7 DYTGT = $(DYSRC:.c=.o)

    8

    9 %.o : %.c

    10 cc -c $?

    11

    12 # 动态库应用示范程序

    13 dy : $(DYTGT)

    14 cc -rdynamic -s -o $@ $(DYTGT) -ldl

    15

    ----------------------------------------------------------------------

    维护文件说明:

    第3行: 定义所有需要维护的模块;

    第5行: 定义源程序;

    第7行: 定义目标文件;

    第9-10行: 定义.o文件依赖于.c文件,维护代码为“cc -c 变动的源文件名”;

    第13-14行: 定义dy依赖于变量DYTGT指示的值,维护代码中采用-rdynamic选项以指定输出文件为动态链接的方式,选项-s指定删除目标文件中的符号表,最后的选项-ldl则指示装配程序ld需要装载dl函数库。

    2.2.3 运行make命令

    运行make后将产生执行文件dy,运行后将产生如下类似信息:

    动态链接库应用示范

    当前日期: 2001-06-28

    当前时间: 10:06:21

    当删除my.so文件时,将出现以下信息:

    动态链接库应用示范

    my.so: cannot open shared object file: 文件或目录不存在

    3、小结

    LINUX创建与使用动态链接库并不是一件难事。

    编译函数源程序时选用-shared选项即可创建动态链接库,注意应以.so后缀命名,最好放到公用库目录(如/lib,/usr/lib等)下面,并要写好用户接口文件,以便其它用户共享。

    使用动态链接库,源程序中要包含dlfcn.h头文件,写程序时注意dlopen等函数的正确调用,编译时要采用-rdynamic选项与-ldl选项,以产生可调用动态链接库的执行代码。

    作者:雨亦奇

    原文转自:http://www.ltesting.net

    展开全文
  • 大家都知道,在WINDOWS系统中有很多的动态链接(以.DLL为后缀的文件,DLL即Dynamic Link Library)。这种动态链接,和静态函数不同,它里面的函数并不是执行程序本身的一部分,而是根据执行程序需要按需装入,...

    大家都知道,在WINDOWS系统中有很多的动态链接库(以.DLL为后缀的文件,DLL即Dynamic Link Library)。这种动态链接库,和静态函数库不同,它里面的函数并不是执行程序本身的一部分,而是根据执行程序需要按需装入,同时其执行代码可在多个执行程序间共享,节省了空间,提高了效率,具备很高的灵活性,得到越来越多程序员和用户的青睐。那么,在LINUX系统中有无这样的函数库呢?

    答案是肯定的,LINUX的动态链接库不仅有,而且为数不少。在/lib目录下,就有许多以.so作后缀的文件,这就是LINUX系统应用的动态链接库,只不过与WINDOWS叫法不同,它叫so,即Shared Object,共享对象。(在LINUX下,静态函数库是以.a作后缀的) X-WINDOW作为LINUX下的标准图形窗口界面,它本身就采用了很多的动态链接库(在/usr/X11R6/lib目录下),以方便程序间的共享,节省占用空间。著名的APACHE网页服务器,也采用了动态链接库,以便扩充程序功能。你只需将PHP动态链接库拷到其共享目录,修改一下配置,APACHE就可以支持PHP网页了。如果你愿意,可以自己编写动态链接库,让APACHE支持你自己定义的网页格式。这就是动态链接的好处。

    1、LINUX下动态链接库的创建

    在LINUX系统下,创建动态链接库是件再简单不过的事情。只要在编译函数库源程序时加上-shared选项即可,这样所生成的执行程序即为动态链接库。从某种意义上来说,动态链接库也是一种执行程序。按一般规则,程序名应带.so后缀。下面举个例子说说。我准备编写两个函数,一个用于查询当前日期getdate,一个用于查询当前时间gettime,并将这两个函数存于动态链接库my.so中。为此,需要做以下几项工作。

    1.1 编写用户接口文件datetime.h,内容如下(每行前面的数字为行号):

    /* datetime.h :*/

    #ifndef __DATETIME_H

    #define __DATETIME_H

    /* 日期结构 */

    typedef struct

    {

    int year;

    int mon;

    int day;

    }DATETYPE;

    /* 时间结构 */

    typedef struct

    {

    char hour;

    char min;

    char sec;

    } TIMETYPE;

    /* 函数原型说明 */

    #ifdef SHARED

    int (*getdate)(DATETYPE *d);

    #else

    int getdate(DATETYPE *d);

    #endif

    #ifdef SHARED

    int (*gettime)(TIMETYPE *t);

    #else

    int gettime(TIMETYPE *t);

    #endif

    #endif

    这个用户接口文件中,先定义了日期与时间结构,接着定义一下函数的原型。动态函数与静态函数的原型说明不同的是,动态函数应使用(*函数名)的形式,以便引用其指针。若要引用文件中的动态函数说明,用户应该定义一下SHARED宏,这样才能使用。

    1.2 编写getdate.c,源程序如下:

    /* getdate.c : */

    #include "time.h"

    #include "datetime.h"

    int getdate(DATETYPE *d)

    {

    long ti;

    struct tm *tm;

    time(&ti);

    tm=localtime(&ti);

    d->year=tm->tm_year+1900;

    d->mon=tm->tm_mon+1;

    d->day=tm->tm_mday;

    }

    在getdate函数中,先调用time取得以秒计的系统时间,再用localtime函数转换一下时间结构,最后调整得到正确的日期。

    1.3 编写gettime.c,源程序如下:

    /* gettime.c :  */

    #include "time.h"

    #include "datetime.h"

    int gettime(TIMETYPE *t)

    {

    long ti;

    struct tm *tm;

    time(&ti);

    tm=localtime(&ti);

    t->hour=tm->tm_hour;

    t->min=tm->tm_min;

    t->sec=tm->tm_sec;

    }

    gettime函数与getdate函数相仿,先用time函数取得以秒计的系统时间,再用localtime函数转换一下时间结构,最后返回当前的时间(不需调整)。

    1.4 编写维护文件makefile-lib,内容如下:

    # makefile-lib : .

    all : my.so

    SRC = getdate.c gettime.c

    TGT = $(SRC:.c=.o)

    $(SRC) : datetime.h

    @touch $@

    %.o : %.c

    cc -c $?

    # 动态函数库(my.so)生成

    my.so : $(TGT)

    cc -shared -o $@ $(TGT)

    编写维护文件的目的,在于方便程序员维护程序,尤其是维护比较大的工程项目。一个素质良好的程序员应该学会熟练地编写维护文件makefile。定义了文件间的依赖关系后,一旦源文件发生变化,仅需make一下,其目标文件维护代码会自动执行,从而自动更新目标文件,减少了许多工作量。

    注意: 每行维护代码必须以TAB(跳格键)开始,不是的话make时将出错。本维护文件第1行是注释行,以#号开头;

    文件第3行定义所有需要维护的函数库;

    第5行定义相关源程序文件;第7行定义目标文件;

    第9-10行说明所有源程序依赖于datetime.h头文件,并有相应维护代码,即touch一下,更新一下源文件的时间;

    第12-13行定义.o文件依赖于相应的.c文件,并指定了维护代码,即用cc编译一下;

    第16-17行定义共享库my.so依赖的目标文件,维护代码中用-shared编译选项,以生成动态链接库my.so。

    1.5 运行make -f makefile-lib 命令

    make运行后,动态链接库my.so就产生了,我们就可以在程序中调用了。如果想让系统所有用户都可以使用,则应以root用户登录系统,将这个库拷贝到/lib目录下(命令:cp my.so /lib),或者在/lib目录下建个符号连接即可(命令:ln -s `pwd`/my.so /lib)。

    2、LINUX下动态链接库的使用

    2.1 重要的dlfcn.h头文件

    LINUX下使用动态链接库,源程序需要包含dlfcn.h头文件,此文件定义了调用动态链接库的函数的原型。下面详细说明一下这些函数。

    2.1.1 dlerror

    原型为: const char *dlerror(void);

    当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为

    NULL时表示操作函数执行成功。

    2.1.2 dlopen

    原型为: void *dlopen (const char *filename, int flag);

    dlopen用于打开指定名字(filename)的动态链接库,并返回操作句柄。

    filename: 如果名字不以/开头,则非绝对路径名,将按下列先后顺序查找该

    文件。

    (1) 用户环境变量中的LD_LIBRARY值;

    (2) 动态链接缓冲文件/etc/ld.so.cache

    (3) 目录/lib,/usr/lib

    flag表示在什么时候解决未定义的符号(调用)。取值有两个:

    1) RTLD_LAZY : 表明在动态链接库的函数代码执行时解决。

    2) RTLD_NOW : 表明在dlopen返回前就解决所有未定义的符号,一旦未解决,dlopen将返回错误。

    dlopen调用失败时,将返回NULL值,否则返回的是操作句柄。

    2.1.3 dlsym : 取函数执行地址

    原型为: void *dlsym(void *handle, char *symbol);

    dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函

    数的执行代码地址。由此地址,可以带参数执行相应的函数。

    如程序代码: void (*add)(int x,int y); /* 说明一下要调用的动态函数add */

    add=dlsym("xxx.so","add"); /* 打开xxx.so共享库,取add函数地址 */

    add(89,369); /* 带两个参数89和369调用add函数 */

    2.1.4 dlclose : 关闭动态链接库

    原型为: int dlclose (void *handle);

    dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。

    2.2 在程序中使用动态链接库函数

    2.2.1 程序范例

    下面的程序装载了动态链接库my.so,并用getdate,gettime取得当前日期与

    时间后输出。

    #include "stdio.h" /* 包含标准输入输出文件 */

    #include "dlfcn.h" /* 包含动态链接功能接口文件 */

    #define SOFILE "./my.so" /* 指定动态链接库名称 */

    #define SHARED /* 定义宏,确认共享,以便引用动态函数 */

    #include "datetime.h" /* 包含用户接口文件 */

    main()

    {

    DATETYPE d;

    TIMETYPE t;

    void *dp;

    char *error;

    puts("动态链接库应用示范");

    dp=dlopen(SOFILE,RTLD_LAZY); /* 打开动态链接库 */

    if (dp==NULL) /* 若打开失败则退出 */

    {

    fputs(dlerror(),stderr);

    exit(1);

    }

    getdate=dlsym(dp,"getdate"); /* 定位取日期函数 */

    error=dlerror(); /* 检测错误 */

    if (error) /* 若出错则退出 */

    {

    fputs(error,stderr);

    exit(1);

    }

    getdate(&d); /* 调用此共享函数 */

    printf("当前日期: %04d-%02d-%02d

    ",d.year,d.mon,d.day);

    gettime=dlsym(dp,"gettime"); /* 定位取时间函数 */

    error=dlerror(); /* 检测错误 */

    if (error) /* 若出错则退出 */

    {

    fputs(error,stderr);

    exit(1);

    }

    gettime(&t); /* 调用此共享函数 */

    printf("当前时间: %02d:%02d:%02d

    ",t.hour,t.min,t.sec);

    dlclose(dp); /* 关闭共享库 */

    exit(0); /* 成功返回 */

    }

    程序说明:

    第8行: 包含标准输入输出头文件,因为程序中使用了printf,puts,fputs等标准输入输出函数,需要让编译器根据头文件中函数的原型,检查一下语法;

    第10-11行: 包含动态链接库功能头文件,并定义动态链接库名称;

    第13-14行: 定义宏SHARED以便引用14行的头文件datetime.h中的动态函数说明;

    第25行: 用dlopen打开SOFILE共享库,返回句柄dp;

    第27-31行: 检测dp是否为空,为空则显示错误后退出;

    第33行: 用dlsym取得getdate函数动态地址;

    第35-40行: 如果dlerror返回值不为空,则dlsym执行出错,程序显示错误后退出;

    第42-43行: 执行getdate调用,输出当前日期;

    第45行: 用dlsym取得gettime函数动态地址;

    第47-52行: 如果dlerror返回值不为空,则dlsym执行出错,程序显示错误后退出;

    第54-55行: 执行gettime调用,输出当前时间;

    第57行: 用dlclose关闭dp所指示的动态链接库;

    第59行: 程序退出,返回0值。

    2.2.2 编写维护文件

    维护文件makefile内容如下:

    # makefile : 纵横软件制作中心雨亦奇编写, 2001-06-28.

    all : dy

    DYSRC = dy.c

    DYTGT = $(DYSRC:.c=.o)

    %.o : %.c

    cc -c $?

    # 动态库应用示范程序

    dy : $(DYTGT)

    cc -rdynamic -s -o $@ $(DYTGT) -ldl

    维护文件说明:

    第3行: 定义所有需要维护的模块;

    第5行: 定义源程序;

    第7行: 定义目标文件;

    第9-10行: 定义.o文件依赖于.c文件,维护代码为“cc -c 变动的源文件名”;

    第13-14行: 定义dy依赖于变量DYTGT指示的值,维护代码中采用-rdynamic选项以指定输出文件为动态链接的方式,选项-s指定删除目标文件中的符号表,最后的选项-ldl则指示装配程序ld需要装载dl函数库。

    2.2.3 运行make命令

    运行make后将产生执行文件dy,运行后将产生如下类似信息:

    动态链接库应用示范

    当前日期: 2001-06-28

    当前时间: 10:06:21

    当删除my.so文件时,将出现以下信息:

    动态链接库应用示范

    my.so: cannot open shared object file: 文件或目录不存在

    3、小结

    LINUX创建与使用动态链接库并不是一件难事。编译函数源程序时选用-shared选项即可创建动态链接库,注意应以.so后缀命名,最好放到公用库目录(如/lib,/usr/lib等)下面,并要写好用户接口文件,以便其它用户共享。使用动态链接库,源程序中要包含dlfcn.h头文件,写程序时注意dlopen等函数的正确调用,编译时要采用-rdynamic选项与-ldl选项,以产生可调用动态链接库的执行代码。

    展开全文
  • linux库文件的编写本文主要参考了如下资料⑴hcj写的"Linux静态/动态链接库的创建和使用"地址⑵雨亦奇的文章"LINUX动态链接库高级应用"地址)在此一并致谢。一、为什么要使用库文件 我们在实际编程工作中肯定会遇到...
  • LINUX动态链接高级应用在《LINUX下动态链接的创建与应用》 一文中,我介绍了LINUX动态链接的基本知识.其要点是:用户根据实际情况需要,利用dlopen,dlsym,dlclose等动态链接操作函 数,装入指定的动态链接中...
  • 1.什么是库库lib是编译好的二进制代码,可以被操作系统载入内存执行,一般是预先编译好的函数的集合,可以通过头文件链接到库文件,执行已经编译好的代码段。库一般分为静态库(static lib,在linux系统一般是.a文件)...
  • Delphi 编写DLL动态链接库文件的知识和样例(有详细步骤,很清楚) 一.DLL动态链接库文件的知识简介: Windows的发展要求允许同时运行的几个程序共享一组函数的单一拷贝.动态链接库就是在这种情况下出现的.动态链接...
  • Linux静态库和动态库

    2021-11-28 17:23:06
    我们通常把公用的自定义函数和类从主程序中分离出来,函数和类的声明在头文件中,定义在程序文件中,主程序中要包含头文件,编译时要和程序文件一起编译。 示例(public.h) #ifndefPUBLIC_H #definePUBLIC_H1 ...
  • wzcdlg.dll 是系统文件,不要删除文件wzcdlg.dll 包含在以下软件* Windows XP Home Edition, Deutsch 更多信息版本: 5.1.2600.1276文件日期: 2003-09-26 21:14:23文件大小: 58.368 字节文件道路: C:\WINDOWS\system...
  • PyInstaller是一个十分有用的第三方,它能够在Windows、Linux、MacOSX等操作系统下将Python源文件打包(或生成.exe文件),通过对源文件打包,Python程序可以在没有安装Python的环境中运行,也可以作为一个独立文件...
  • 下面给大家介绍下pandas读取CSV文件时查看修改各列的数据类型格式,具体内容如下所述:我们在调bug的时候会经常查看、修改pandas列数据的数据类型,今天就总结一下:1.查看:Numpy和Pandas的查看方式略有不同,一个...
  • axChart,一套支持Axure RP8/9的动态可视化图表元件。元件的能力,请查看本元件提供的【在线演示】,直观感受axChart的强大配置能力。2020.07.10 v1.2.3更新•新增象形图,包括基础象形图、裁剪象形图和分组象形图...
  • Mercurial hg web server的配置 在windows下安装tortoisehg-1.0.3-hg-1.5.3-x64.exe的版本控制工具后,克隆建立中心后,启动web server,其他分可以连接中心进行pull但无法push. ... 【leetcode】经典算法题-...
  • 动态链接库文件在windows平台下往往以.dll为后缀,而在linux平台则一般以.so为后缀,so是shared object的缩写。采用gcc编译器,文件:adpcm.h, adpcm.c, main.c, 放在同一目录下(/home/hbapril)想做到windows和linux...
  • 设置 "workbench.editor.enablePreview": false…主要是...多出的文件 ) 现在还不会写GUI,打算后面自己做目录树diff,可以手动点选要复制的文件. 同时我也知道有现成的软件,比如meld,但是windows下面不太好用. 特性: ...
  • kendoUI2018最新版库文件中的日期插件,支持多选。需要按着CTRL键,这样用户选时间的时候,可选多天(可连续也可不连续)。更多详情可百度kendoUI官方文档,在这里,因项目使用的是老版本的kendo,为避免不必要的麻烦...
  • Linux -- date 日期命令

    2021-05-18 00:22:16
    Linux --date 日期命令date 用法:date [选项]... [+格式]以给定的格式显示当前时间,或是设置系统日期。1.使用 date 命令查看当前日期或当前时间[root@localhost ~]# date2019年 01月 10日 星期四 :: CST[root@...
  • Openpyxl能够读取和修改.xls文件,使用Openpyxl前先要掌握三个对象,即:Workbook(工作簿,一个包含多个Sheet的Excel文件) 2021-02-02 23:48:42 1、常规写入# -*- encoding=utf-8 -*-import xlwtif __name__ == '__...
  • Mac命令行常用操作

    2021-01-27 06:51:37
    Mac系统目录结构符合unix传统目录/bin 传统unix命令的存放目录,如ls.../usr/bin, /usr/sbin, /usr/lib,其中/usr/lib目录中存放了共享(动态链接)./etc. 标准unix系统配置文件存放目录,如用户密码文件/etc/pass...
  • python封装成软件后怎么改参数打pycharm工具,新建python文件;在文件中,使用from...import导入Flask,request,jsonify请点入图片描述定个json格式的数据,包含了姓名、年龄和性别请点击输入图片描述调用Flask,使用...
  • Linux---文件操作

    2021-10-11 11:45:05
    文件操作C语言中的文件读&写stdinstdoutstderra--追加写入write-- 覆盖写入系统中的I/O三级目录 C语言中的文件读&写 #include <stdio.h> int main() { FILE* fp = fopen("log.txt","r"); if(fp ==...
  • 就会更改这个读取时间,例如用cat去读取文件 默认情况下,ls显示出来是该文件的mtime $ touch [-acdmt] 文件 # 参数 -a: 仅修改访问时间 # -c: 仅修改文件的时间,当文件不存在则不创建新文件 # -d: 后面可以接欲...
  • 解析Apache配置文件

    2021-04-26 11:58:10
    2、检查程序目录是否有除了应用程序以外的其他文件,比如tar.gz压缩包,一些无用日志、txt文件、以bak或者日期为后缀的备份文件、脚本等。可以通过 find ./htdocs/ -name *\.*\.*来查看是否有一些特殊文件,如果...
  • mybatis配置文件详解

    2021-01-27 09:17:57
    参见:https://www.cnblogs.com/black-spike/p/7765732.html1. 元素是一个配置属性的元素,该元素通常用来将内部的配置外在化,即通过外部的配置来动态的替换内部定义的属性。例如:数据库的连接属性,就可以通过专门...
  • 一、动态表头easyExcel导出。 上次用easyExcel做了个动态表头导入(https://blog.csdn.net/qq_37337660/article/details/110288393),不过,当时用的版本过低,并且也没有详细说明,这次整了个easyExcel动态表头的...
  • HookAPI同样也适用于截获用户自己编写的DLL文件中的输出函数。1.5系统特点:1)自己编写的替代函数的参数形式和原API函数完全一样,方便了Delphi和VB用户的使用。2)实时截获所有新建立的进程,即进程建立后马上安装...
  • 1.生成一个空的2MiB文件dd if=/dev/zero of=rootfs.ext4 bs=1024 count=2048 (指定每一块大小为1024字节,一共又2048块,那么就是2048 * 1024 B = 2MiB)2.对生成的文件进行格式化mkfs.ext4 rootfs.ext43.挂载此空...
  • Linux文件与目录管理

    2021-05-11 21:03:59
    [TOC]# Linux文件与目录管理## 1 目录的相关操作### 1.1 `cd`:切换目录### 1.2 `pwd`:显示当前目录### 1.3 `mkdir`:新建一个新的目录### 1.4 `rmdir`:删除一个空的目录## 2 文件与目录管理### 2.1 `ls`:查看...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 62,410
精华内容 24,964
关键字:

动态库文件修改日期