精华内容
下载资源
问答
  • 转自:... 一、基本概念 1.1、什么是 ... 在 windows 平台和 linux 平台都大量存在着。  本质上来说是一种可执行二进制代码(但不可以独立执行),可以被操作系统载入内存执行。

    转自:http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520101023104745738/

    一、基本概念

    1.1、什么是库

           在 windows 平台和 linux 平台下都大量存在着库。

           本质上来说库是一种可执行的二进制代码(但不可以独立执行),可以被操作系统载入内存执行

           由于 windows 和 linux 的平台不同(主要是编译器、汇编器和连接器 的不同),因此二者库的二进制是不兼容的。

           本文仅限于介绍 linux 下的库。

    1.2、 库的种类

          linux 下的库有两种:静态库共享库(动态库)。

       二者的不同点在于代码被载入的时刻不同:

       静态库的代码在编译过程中已经被载入可执行程序,因此生成的可执行程序体积较大。静态用.a为后缀, 例如: libhello.a

       共享库(动态库)的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此生成的可执行程序代码体积较小。

       动态通常用.so为后缀, 例如:libhello.so

          共享库(动态库)的好处是:: 不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。

          为了在同一系统中使用不同版本的库,可以在库文件名后加上版本号为后缀,例如: libhello.so.1.0,由于程序连接默认以.so为文件后缀名。所以为了使用这些库,通常使用建立符号连接的方式。

          ln -s libhello.so.1.0 libhello.so.1 

          ln -s libhello.so.1 libhello.so

    1.3、静态库,动态库文件在linux下是如何生成的:
    以下面的代码为例,生成上面用到的hello库:
    /* hello.c */  
    #include "hello.h"  
    void sayhello()  
    {      
        printf("hello,world ");  
    }

    首先用gcc编绎该文件,在编绎时可以使用任何合法的编绎参数,例如-g加入调试代码等:

    gcc -c hello.c -o hello.o

    1、生成静态库 生成静态库使用ar工具,其实ar是archive的意思

    ar cqs libhello.a hello.o

    2、生成动态库 用gcc来完成,由于可能存在多个版本,因此通常指定版本号:

    gcc -shared -o libhello.so.1.0 hello.o
     
    1.4、库文件是如何命名的,有没有什么规范: 
    在 linux 下,库文件一般放在/usr/lib和/lib下, 
    静态库的名字一般为libxxxx.a,其中 xxxx 是该lib的名称;
    动态库的名字一般为libxxxx.so.major.minor,xxxx 是该lib的名称,major是主版本号,minor是副版本号
     
    1.5、可执行程序在执行的时候如何定位共享库(动态库)文件 :
        当系统加载可执行代码(即库文件)的时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径,此时就需要系统动态载入器 (dynamic linker/loader) 
        对于 elf 格式的可执行程序,是由 ld-linux.so* 来完成的,它先后搜索 elf 文件的 DT_RPATH 段-->环境变量LD_LIBRARY_PATH—->/etc/ld.so.cache 文件列表--> /lib/,/usr/lib 目录找到库文件后将其载入内存
        如: export LD_LIBRARY_PATH=’pwd’ 
        将当前文件目录添加为共享目录。
     
    1.6、使用ldd工具,查看可执行程序依赖那些动态库或着动态库依赖于那些动态库
       ldd 命令可以查看一个可执行程序依赖的共享库, 
        例如 # ldd /bin/lnlibc.so.6 
            => /lib/libc.so.6 (0×40021000)/lib/ld-linux.so.2 
            => /lib/ld- linux.so.2 (0×40000000) 
       可以看到 ln 命令依赖于 libc 库和 ld-linux 库 
     
    1.7、使用nm工具,查看静态库动态库有那些函数名;
        T类表示函数是当前库中定义的U类表示函数是被调用的,在其它库中定义的W类当前库中定义,被其它库中的函数覆盖)。
        有时候可能需要查看一个库中到底有哪些函数,nm工具可以打印出库中的涉及到的所有符号,这里的库既可以是静态的也可以是动态的。

    nm列出的符号有很多, 常见的有三种::

    T类:库中定义的函数,用T表示,这是最常见的

    U类:在库中被调用,但并没有在库中定义(表明需要其他库支持),用U表示

    W类:是所谓的“弱态”符号,它们虽然在库中被定义,但是可能被其他库中的同名符号覆盖,用W表示

    例如,假设开发者希望知道上文提到的hello库中是否引用了 printf():

       nm libhello.so | grep printf 

    发现printf是U类符号,说明printf被引用,但是并没有在库中定义。

    由此可以推断,要正常使用hello库,必须有其它库支持,使用ldd工具查看hello依赖于哪些库:

    ldd libhello.so

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

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

    从上面的结果可以继续查看printf最终在哪里被定义,有兴趣可以go on

     

    1.8、使用ar工具,可以生成静态库,同时可以查看静态库中包含那些.o文件,即有那些源文件构成

    可以使用 ar -t libname.a 来查看一个静态库由那些.o文件构成。

    可以使用 ar q libname.a xxx1.o xxx2.o xxx3.o ... xxxn.o 生成静态库

     

    1.9、如何查看动态库和静态库是32位,还是64位下的库:

    如果是动态库,可以使用file *.so;

    如果是静态哭,可以使用objdump -x *.a

     

    Linux下进行程序设计时,关于库的使用:
    一、gcc/g++命令中关于库的参数:
        -shared: 该选项指定生成动态连接库;
        -fPIC:表示编译为位置独立(地址无关)的代码,不用此选项的话,编译后的代码是位置相关的,所以动态载入时,是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
        -L:指定链接库的路径,-L. 表示要连接的库在当前目录中
        -ltest:指定链接库的名称为test,编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称
        -Wl,-rpath: 记录以来so文件的路径信息。
        LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。
         当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来达到同样的目的,
         不过如果没有root权限,那么只能采用修改LD_LIBRARY_PATH环境变量的方法了。 
    调用动态库的时候,有几个问题会经常碰到:
        1、有时,明明已经将库的头文件所在目录 通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so文件,这时你要作的就是通过修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录。通常这样做就可以解决库无法链接的问题了。
     
    二、静态库链接时搜索路径的顺序: 
       1. ld会去找gcc/g++命令中的参数-L;
       2. 再找gcc的环境变量LIBRARY_PATH,它指定程序静态链接库文件搜索路径;
          export LIBRARY_PATH=$LIBRARY_PATH:data/home/billchen/lib 
       3. 再找默认库目录 /lib  /usr/lib  /usr/local/lib,这是当初compile gcc时写在程序内的。 
       
    三、动态链接时、执行时搜索路径顺序: 
        1. 编译目标代码时指定的动态库搜索路径;
        2. 环境变量LD_LIBRARY_PATH指定动态库搜索路径,它指定程序动态链接库文件搜索路径;
          export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:data/home/billchen/lib 
        3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径;
        4. 默认的动态库搜索路径/lib;
        5. 默认的动态库搜索路径/usr/lib。 
     
    四、静态库和动态链接库同时存在时,gcc/g++默认链接的是动态库:
        当一个库同时存在静态库和动态库时,比如libmysqlclient.a和libmysqlclient.so同时存在时:
        在Linux下,动态库和静态库同事存在时,gcc/g++的链接程序,默认链接的动态库
    
        可以使用下面的方法,给连接器ld传递参数,看是否链接动态库还是静态库。
    
        -Wl,-Bstatic -llibname        //指定让gcc/g++链接静态库
        使用:
        gcc/g++ test.c -o test -Wl,-Bstatic -llibname -Wl,-Bdynamic -lm -lc 
    
        -Wl,-Bdynamic -llibname       //指定让gcc/g++链接动态库
        使用:
        gcc/g++ test.c -o test -Wl,-Bdynamic -llibname
       如果要完全静态加在,使用-static参数,即将所有的库以静态的方式链入可执行程序,这样生成的可执行程序,不再依赖任何库,同事出现的问题是,这样编译出来的程序非常大,占用空间。
    如果不适用-Wl,-Bdynamic -lm -c会有如下错误:
    [chenbaihu@build17 lib]$ ls
    libtest.a  libtest.so  t  t.cc  test.cc  test.h  test.o
    [chenbaihu@build17 lib]$ g++ -Wall -g t.cc -o t -L./ -Wl,-Bstatic -ltest -Wl,-Bdynamic -lm -lc
    [chenbaihu@build17 lib]$ g++ -Wall -g t.cc -o t -L./ -Wl,-Bstatic -ltest 
    /usr/bin/ld: cannot find -lm
    collect2: ld 返回 1
    参考:
         http://lists.gnu.org/archive/html/help-gnu-utils/2004-03/msg00009.html

    五、有关环境变量: 
        LIBRARY_PATH环境变量:指定程序静态链接库文件搜索路径
        LD_LIBRARY_PATH环境变量:指定程序动态链接库文件搜索路径 
     
    六、库的依赖问题:
       比如我们有一个基础库libbase.a,还有一个依赖libbase.a编译的库,叫做libchild.a;在我们编译程序时,一定要先-lchild再-lbase。 如果使用 -lbase -lchild,在编译时将出现一些函数undefined,而这些函数实际上已经在base中已经定义;
       为什么会有库的依赖问题?
       一、静态库解析符号引用:
          链接器ld是如何使用静态库来解析引用的。在符号解析阶段,链接器从左至右,依次扫描可重定位目标文件(*.o)静态库(*.a)在这个过程中,链接器将维持三个集合:
       集合E:可重定位目标文件(*.o文件)的集合。
       集合U:未解析(未定义)的符号集,即符号表中UNDEF的符号。
       集合D: 已定义的符号集。
       初始情况下,E、U、D均为空。
       1、对于每个输入文件f,如果是目标文件(.o),则将f加入E,并用f中的符号表修改U、D(在文件f中定义实现的符号是D,在f中引用的符号是U),然后继续下个文件。
       2、如果f是一个静态库(.a),那么链接器将尝试匹配U中未解析符号与静态库成员(静态库的成员就是.o文件)定义的符号。如果静态库中某个成员m(某个.o文件)定义了一个符号来解析U中引用,那么将m加入E中,
       同时使用m的符号表,来更新U、D。对静态库中所有成员目标文件反复进行该过程,直至U和D不再发生变化。此时,静态库f中任何不包含在E中的成员目标文件都将丢弃,链接器将继续下一个文件。
       3、当所有输入文件完成后,如果U非空,链接器则会报错,否则合并和重定位E中目标文件,构建出可执行文件。
     到这里,为什么会有库的依赖问题已经得到解答:
     因为libchild.a依赖于libbase.a,但是libbase.a在libchild.a的左边,导致libbase.a中的目标文件(*.o)根本就没有被加载到E中,所以解决方法就是交换两者的顺序。当然也可以使用-lbase -lchild -lbase的方法。
    参考文章:http://pananq.com/index.php/page/3/
     
    七、动态库升级问题:
       在动态链接库升级时,
       不能使用cp newlib.so oldlib.so,这样有可能会使程序core掉;
       而应该使用:
       rm oldlib.so 然后 cp newlib.so oldlib.so
       或者
        mv oldlib.so oldlib.so_bak 然后 cp newlib.so oldlib.so
    

    为什么不能用cp newlib.so oldlib.so ?

    在替换so文件时,如果在不停程序的情况下,直接用 cp new.so old.so 的方式替换程序使用的动态库文件会导致正在运行中的程序崩溃。

    解决方法:

    解决的办法是采用“rm+cp” 或“mv+cp” 来替代直接“cp” 的操作方法。

    linux系统的动态库有两种使用方法:运行时动态链接库,动态加载库并在程序控制之下使用。

    1、为什么在不停程序的情况下,直接用 cp 命令替换程序使用的 so 文件,会使程序崩溃? 很多同学在工作中遇到过这样一个问题,在替换 so 文件时,如果在不停程序的情况下,直接用cp new.so old.so的方式替换程序使用的动态库文件会导致正在运行中的程序崩溃,退出。

    这与 cp 命令的实现有关,cp 并不改变目标文件的 inode,cp 的目标文件会继承被覆盖文件的属性而非源文件。实际上它是这样实现的: strace cp libnew.so libold.so 2>&1 |grep open.*lib.*.so open("libnew.so", O_RDONLY|O_LARGEFILE) = 3 open("libold.so", O_WRONLY|O_TRUNC|O_LARGEFILE) = 4 在 cp 使用“O_WRONLY|O_TRUNC” 打开目标文件时,原 so 文件的镜像被意外的破坏了。这样动态链接器 ld.so 不能访问到 so 文件中的函数入口。从而导致 Segmentation fault,程序崩溃。ld.so 加载 so 文件及“再定位”的机制比较复杂。

    2、怎样在不停止程序的情况下替换so文件,并且保证程序不会崩溃? 答案是采用“rm+cp” 或“mv+cp” 来替代直接“cp” 的操作方法。

    在用新的so文件 libnew.so 替换旧的so文件 libold.so 时,如果采用如下方法: rm libold.so //如果内核正在使用libold.so,那么inode节点不会立刻别删除掉。 cp libnew.so libold.so 采用这种方法,目标文件 libold.so 的 inode 其实已经改变了,原来的 libold.so 文件虽然不能用"ls"查看到,但其inode并没有被真正删除,直到内核释放对它的引用。

    (即: rm libold.so,此时,如果ld.so正在加在libold.so,内核就在引用libold.so的inode节点,rm libold.so的inode并没有被真正删除,当ld.so对libold.so的引用结束,inode才会真正删除。这样程序就不会崩溃,因为它还在使用旧的libold.so,当下次再使用libold.so时,已经被替换,就会使用新的libold.so)

    同理,mv只是改变了文件名,其 inode 不变,新文件使用了新的 inode。这样动态链接器 ld.so 仍然使用原来文件的 inode 访问旧的 so 文件。因而程序依然能正常运行。

    (即: mv libold.so ***后,如果程序使用动态库,还是使用旧的inode节点,当下次再使用libold.so时,就会使用新的libold.so)

    到这里,为什么直接使用“cp new_exec_file old_exec_file”这样的命令时,系统会禁止这样的操作,并且给出这样的提示“cp: cannot create regular file `old': Text file busy”。

    这时,我们采用的办法仍然是用“rm+cp”或者“mv+cp”来替代直接“cp”,这跟以上提到的so文件的替换有同样的道理

    但是,为什么系统会阻止cp覆盖可执行程序,而不阻止覆盖so文件

    这是因为 Linux 有个 Demand Paging 机制,所谓“Demand Paging”,简单的说,就是系统为了节约物理内存开销,并不会程序运行时就将所有页(page)都加载到内存中,而只有在系统有访问需求时才将其加载。“Demand Paging”要求正在运行中的程序镜像注意,并非文件本身不被意外修改因此内核在启动程序后会锁定这个程序镜像的 inode

    对于 so 文件,它是靠 ld.so 加载的,而ld.so毕竟也是用户态程序,没有权利去锁定inode,也不应与内核的文件系统底层实现耦合。

    展开全文
  • Linux下静态_库的基本概念;...nm查看库中包含那些函数、ar生成静态查看库中包含那些.o文件、ldd查看程序依赖.so文件;gcc/g++与相关参数-L,-l,-fPIC,-shared;静态链接时搜索过程;

    from :http://www.cppblog.com/tqsheng/archive/2013/01/04/196948.aspx


    Linux下静态库_库的基本概念;如何生成静态库动态库;nm查看库中包含那些函数、ar生成静态库,查看库中包含那些.o文件、ldd查看程序依赖的.so文件;gcc/g++与库相关的参数-L,-l,-fPIC,-shared;静态库链接时搜索过程;动态库链接时,加载时搜索的过程;动态库找不到的问题;动态库升级步骤

    Linux下静态库_库的基本概念;如何生成静态库动态库;nm查看库中包含那些函数、ar生成静态库,查看库中包含那些.o文件、ldd查看程序依赖的.so文件;gcc/g++与库相关的参数-L,-l,-fPIC,-shared;静态库链接时搜索过程;动态库链接时,加载时搜索的过程;动态库找不到的问题;动态库升级步骤

    2010-11-23 10:47:45| 分类: Linux系统编程 | 标签: |字号 订阅

    一、基本概念

    1.1、什么是库

    在 windows 平台和 linux 平台下都大量存在着库。

    本质上来说库是 一种可执行代码的二进制形式,可以被操作系统载入内存执行

    由于 windows 和 linux 的平台不同(主要是编译器、汇编器和连接器 的不同),因此二者库的二进制是不兼容的。

    本文仅限于介绍 linux 下的库。

     

    1.2、 库的种类

    linux 下的库有两种:静态库和共享库(动态库)。

    二者的不同点在于代码被载入的时刻不同。

    静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。

    静态用.a为后缀, 例如: libhello.a

    共享库(动态库)的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。

    动态通常用.so为后缀, 例如:libhello.so

    共享库(动态库)的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。

    为了在同一系统中使用不同版本的库,可以在库文件名后加上版本号为后缀,例如: libhello.so.1.0,由于程序连接默认以.so为文件后缀名。所以为了使用这些库,通常使用建立符号连接的方式。

    ln -s libhello.so.1.0 libhello.so.1 ln -s libhello.so.1 libhello.so

    1.3、静态库,动态库文件在linux下是如何生成的:
    以下面的代码为例,生成上面用到的hello库:
    /* hello.c */  
    #include "hello.h"  
    void sayhello()  
    {      
        printf("hello,world ");  
    }

    首先用gcc编绎该文件,在编绎时可以使用任何合法的编绎参数,例如-g加入调试代码等:

    $gcc -c hello.c -o hello.o

    1、生成静态库 生成静态库使用ar工具,其实ar是archive的意思

    $ar cqs libhello.a hello.o

    2、生成动态库 用gcc来完成,由于可能存在多个版本,因此通常指定版本号:

    $gcc -shared -o libhello.so.1.0 hello.o
     
    1.4、库文件是如何命名的,有没有什么规范: 
    在 linux 下,库文件一般放在/usr/lib和/lib下, 
    静态库的名字一般为libxxxx.a,其中 xxxx 是该lib的名称;
    动态库的名字一般为libxxxx.so.major.minor,xxxx 是该lib的名称,major是主版本号,minor是副版本号 
     
    1.5、可执行程序在执行的时候如何定位共享库(动态库)文件 :
        当系统加载可执行代码(即库文件)的时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径,此时就需要系统动态载入器 (dynamic linker/loader) 
        对于 elf 格式的可执行程序,是由 ld-linux.so* 来完成的,它先后搜索 elf 文件的 DT_RPATH 段—环境变量LD_LIBRARY_PATH—/etc/ld.so.cache 文件列表— /lib/,/usr/lib 目录找到库文件后将其载入内存
        如: export LD_LIBRARY_PATH=’pwd’ 
        将当前文件目录添加为共享目录 
     
    1.6、使用ldd工具,查看可执行程序依赖那些动态库或着动态库依赖于那些动态库
       ldd 命令可以查看一个可执行程序依赖的共享库, 
        例如 # ldd /bin/lnlibc.so.6 
            => /lib/libc.so.6 (0×40021000)/lib/ld-linux.so.2 
            => /lib/ld- linux.so.2 (0×40000000) 
        可以看到 ln 命令依赖于 libc 库和 ld-linux 库 
     
    1.7、使用nm工具,查看静态库和动态库中有那些函数名(T类表示函数是当前库中定义的,U类表示函数是被调用的,在其它库中定义的,W类是当前库中定义,被其它库中的函数覆盖)。
        有时候可能需要查看一个库中到底有哪些函数,nm工具可以打印出库中的涉及到的所有符号,这里的库既可以是静态的也可以是动态的。

    nm列出的符号有很多, 常见的有三种::

    一种是在库中被调用,但并没有在库中定义(表明需要其他库支持),用U表示

    一种是在库中定义的函数,用T表示,这是最常见的

    另外一种是所 谓的“弱态”符号,它们虽然在库中被定义,但是可能被其他库中的同名符号覆盖,用W表示

    例如,假设开发者希望知道上文提到的hello库中是否引用了 printf():

        $nm libhello.so | grep printf 

    发现printf是U类符号,说明printf被引用,但是并没有在库中定义。

    由此可以推断,要正常使用hello库,必须有其它库支持,使用ldd工具查看hello依赖于哪些库:

    $ldd hello libc.so.6=>/lib/libc.so.6(0x400la000) /lib/ld-linux.so.2=>/lib/ld-linux.so.2 (0x40000000)

    从上面的结果可以继续查看printf最终在哪里被定义,有兴趣可以go on

    1.8、使用ar工具,可以生成静态库,同时可以查看静态库中包含那些.o文件,即有那些源文件构成

    可以使用 ar -t libname.a 来查看一个静态库由那些.o文件构成。

    可以使用 ar q libname.a xxx1.o xxx2.o xxx3.o ... xxxn.o 生成静态库

     
    Linux下进行程序设计时,关于库的使用:
     
    一、gcc/g++命令中关于库的参数:
    -shared: 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件
    -fPIC:表示编译为位置独立(地址无关)的代码,不用此选项的话,编译后的代码是位置相关的,所以动态载入时,是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
    -L:指定链接库的路径,-L. 表示要连接的库在当前目录中
    -ltest:指定链接库的名称为test,编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称
    LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。
       当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来达到同样的目的,
       不过如果没有root权限,那么只能采用修改LD_LIBRARY_PATH环境变量的方法了。 
    调用动态库的时候,有几个问题会经常碰到:
        1、有时,明明已经将库的头文件所在目录 通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so文件,这时你要作的就是通过修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录。通常这样做就可以解决库无法链接的问题了。
     
    二、静态库链接时搜索路径的顺序: 
       1. ld会去找gcc/g++命令中的参数-L;
       2. 再找gcc的环境变量LIBRARY_PATH,它指定程序静态链接库文件搜索路径;
          export LIBRARY_PATH=$LIBRARY_PATH:data/home/billchen/lib 
       3. 再找默认库目录 /lib  /usr/lib  /usr/local/lib,这是当初compile gcc时写在程序内的。 
       
    三、动态链接时、执行时搜索路径顺序: 
        1. 编译目标代码时指定的动态库搜索路径;
        2. 环境变量LD_LIBRARY_PATH指定动态库搜索路径,它指定程序动态链接库文件搜索路径;
          export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:data/home/billchen/lib 
        3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径;
        4. 默认的动态库搜索路径/lib;
        5. 默认的动态库搜索路径/usr/lib。 
     
    四、静态库和动态链接库同时存在的问题:
       当一个库同时存在静态库和动态库时,比如libmysqlclient.a和libmysqlclient.so同时存在时:
        在Linux下,动态库和静态库同事存在时,gcc/g++的链接程序,默认链接的动态库。

    可以使用下面的方法,给连接器传递参数,看是否链接动态库还是静态库。

    -WI,-Bstatic -llibname //指定让gcc/g++链接静态库

    使用:

    gcc/g++ test.c -o test -WI,-Bstatic -llibname

    -WI,-Bdynamic -llibname //指定让gcc/g++链接动态库

    使用:

    gcc/g++ test.c -o test -WI,-Bdynamic -llibname

    如果要完全静态加在,使用-static参数,即将所有的库以静态的方式链入可执行程序,这样生成的可执行程序,不再依赖任何库,同事出现的问题是,这样编译出来的程序非常大,占用空间。

     
    五、有关环境变量: 
        LIBRARY_PATH环境变量:指定程序静态链接库文件搜索路径
        LD_LIBRARY_PATH环境变量:指定程序动态链接库文件搜索路径 
     
    六、动态库升级问题:
       在动态链接库升级时,
       不能使用cp newlib.so oldlib.so,这样有可能会使程序core掉;
       而应该使用:
       rm oldlib.so 然后 cp newlib.so oldlib.so
       或者
        mv oldlib.so oldlib.so_bak 然后 cp newlib.so oldlib.so
    

    为什么不能用cp newlib.so oldlib.so ?

    在替换so文件时,如果在不停程序的情况下,直接用 cp new.so old.so 的方式替换程序使用的动态库文件会导致正在运行中的程序崩溃。

     

    解决方法:

    解决的办法是采用“rm+cp” 或“mv+cp” 来替代直接“cp” 的操作方法。

    linux系统的动态库有两种使用方法:运行时动态链接库,动态加载库并在程序控制之下使用。

     

    1、为什么在不停程序的情况下,直接用 cp 命令替换程序使用的 so 文件,会使程序崩溃? 很多同学在工作中遇到过这样一个问题,在替换 so 文件时,如果在不停程序的情况下,直接用cp new.so old.so的方式替换程序使用的动态库文件会导致正在运行中的程序崩溃,退出。

    这与 cp 命令的实现有关,cp 并不改变目标文件的 inode,cp 的目标文件会继承被覆盖文件的属性而非源文件。实际上它是这样实现的: strace cp libnew.so libold.so 2>&1 |grep open.*lib.*.so open("libnew.so", O_RDONLY|O_LARGEFILE) = 3 open("libold.so", O_WRONLY|O_TRUNC|O_LARGEFILE) = 4 在 cp 使用“O_WRONLY|O_TRUNC” 打开目标文件时,原 so 文件的镜像被意外的破坏了这样动态链接器 ld.so 不能访问到 so 文件中的函数入口。从而导致 Segmentation fault,程序崩溃。ld.so 加载 so 文件及“再定位”的机制比较复杂。

     

    2、怎样在不停止程序的情况下替换so文件,并且保证程序不会崩溃? 答案是采用“rm+cp” 或“mv+cp” 来替代直接“cp” 的操作方法。

    在用新的so文件 libnew.so 替换旧的so文件 libold.so 时,如果采用如下方法: rm libold.so //如果内核正在使用libold.so,那么inode节点不会立刻别删除掉。 cp libnew.so libold.so 采用这种方法,目标文件 libold.so 的 inode 其实已经改变了,原来的 libold.so 文件虽然不能用 ”ls”查看到,但其 inode 并没有被真正删除,直到内核释放对它的引用。

    (即: rm libold.so,此时,如果ld.so正在加在libold.so,内核就在引用libold.so的inode节点,rm libold.so的inode并没有被真正删除,当ld.so对libold.so的引用结束,inode才会真正删除。这样程序就不会崩溃,因为它还在使用旧的libold.so,当下次再使用libold.so时,已经被替换,就会使用新的libold.so)

    同理,mv只是改变了文件名,其 inode 不变,新文件使用了新的 inode。这样动态链接器 ld.so 仍然使用原来文件的 inode 访问旧的 so 文件。因而程序依然能正常运行。

    (即: mv libold.so ***后,如果程序使用动态库,还是使用旧的inode节点,当下次再使用libold.so时,就会使用新的libold.so)

    到这里,为什么直接使用“cp new_exec_file old_exec_file”这样的命令时,系统会禁止这样的操作,并且给出这样的提示“cp: cannot create regular file `old': Text file busy”。这时,我们采用的办法仍然是用“rm+cp”或者“mv+cp”来替代直接“cp”,这跟以上提到的so文件的替换有同样的道理

    但是,为什么系统会阻止 cp 覆盖可执行程序,而不阻止覆盖 so 文件呢

    这是因为 Linux 有个 Demand Paging 机制,所谓“Demand Paging”,简单的说,就是系统为了节约物理内存开销,并不会程序运行时就将所有页(page)都加载到内存中,而只有在系统有访问需求时才将其加载。“Demand Paging”要求正在运行中的程序镜像注意,并非文件本身不被意外修改因此内核在启动程序后会锁定这个程序镜像的 inode

    对于 so 文件,它是靠 ld.so 加载的,而ld.so毕竟也是用户态程序,没有权利去锁定inode,也不应与内核的文件系统底层实现耦合


    展开全文
  • 这时需要查看可执行程序或者动态库中的符号表,动态库的依赖项, Linux 有现成的工具可用:objdump 。 objdump 是 gcc 套件中用来查看 ELF 文件的工具,具体详细用法不进行介绍,此处只讲解如何进行一个动态库和静态...
    

    我们在 Linux 下运行一个程序,有时会无法启动,报缺少某某库。这时需要查看可执行程序或者动态库中的符号表,动态库的依赖项, Linux 有现成的工具可用:objdump 。

    objdump 是 gcc 套件中用来查看 ELF 文件的工具,具体详细用法不进行介绍,此处只讲解如何进行一个动态库和静态库中导出函数的查看。

    1). 查看依赖项:objdump -x xxx.so | grep "NEEDED" 。下面是我查看 libsf_modbus_preproce.so 时的输出截图:

     2). 查看动态符号表: objdump -T xxx.so 。假如想知道 xxx.so 中是否导出了符号 yyy ,那么命令为 objdump -T xxx.so | grep "yyy" 。下面是我查看 libsf_modbus_preproce.so 时的输出截图:

    3). 查看符号表: objdump -t xxx.so 。-T 和 -t 选项在于 -T 只能查看动态符号,如库导出的函数和引用其他库的函数,而 -t 可以查看所有的符号,包括数据段的符号。下面是我查看 libsf_modbus_preproce.so 时的输出截图:


    展开全文
  • nm查看包含那些函数、ar生成静态库,查看包含那些.o文件、ldd查看程序依赖.so文件;gcc/g++与库相关参数-L,-l,-fPIC,-shared;静态库链接时搜索过程;动态库链接时,加载时搜索过程;动态库找不到问题;库...

    Linux下静态库_库的基本概念;如何生成静态库动态库;nm查看库中包含那些函数、ar生成静态库,查看库中包含那些.o文件、ldd查看程序依赖的.so文件;gcc/g++与库相关的参数-L,-l,-fPIC,-shared;静态库链接时搜索过程;动态库链接时,加载时搜索的过程;动态库找不到的问题;库的依赖问题;动态库升级问题与步骤。

    一、基本概念

    1.1、什么是库

           在 windows 平台和 linux 平台下都大量存在着库。

           本质上来说库是一种可执行的二进制代码(但不可以独立执行),可以被操作系统载入内存执行

           由于 windows 和 linux 的平台不同(主要是编译器、汇编器和连接器 的不同),因此二者库的二进制是不兼容的。

           本文仅限于介绍 linux 下的库。

    1.2、库的种类

        linux 下的库有两种:静态库共享库(动态库)。

      二者的不同点在于代码被载入的时刻不同:

       静态库的代码在编译过程中已经被载入可执行程序,因此生成的可执行程序体积较大。静态用.a为后缀, 例如: libhello.a

       共享库(动态库)的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此生成的可执行程序代码体积较小。

      动态通常用.so为后缀, 例如:libhello.so

         共享库(动态库)的好处是:: 不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。

          为了在同一系统中使用不同版本的库,可以在库文件名后加上版本号为后缀,例如: libhello.so.1.0,由于程序连接默认以.so为文件后缀名。所以为了使用这些库,通常使用建立符号连接的方式。

         ln -s libhello.so.1.0 libhello.so.1

          ln -s libhello.so.1 libhello.so

    1.3、静态库,动态库文件在linux下是如何生成的:
    以下面的代码为例,生成上面用到的hello库:
    /* hello.c */  
    #include "hello.h"  
    void sayhello()  
    {      
        printf("hello,world ");  
    }

    首先用gcc编绎该文件,在编绎时可以使用任何合法的编绎参数,例如-g加入调试代码等:

    gcc -c hello.c -o hello.o

    1、生成静态库 生成静态库使用ar工具,其实ar是archive的意思

    ar cqs libhello.a hello.o

    2、生成动态库 用gcc来完成,由于可能存在多个版本,因此通常指定版本号:

    gcc -shared -o libhello.so.1.0 hello.o
     
    1.4、库文件是如何命名的,有没有什么规范: 
    在 linux 下,库文件一般放在/usr/lib和/lib下, 
    静态库的名字一般为libxxxx.a,其中 xxxx 是该lib的名称;
    动态库的名字一般为libxxxx.so.major.minor,xxxx 是该lib的名称,major是主版本号,minor是副版本号
     
    1.5、可执行程序在执行的时候如何定位共享库(动态库)文件 :
        当系统加载可执行代码(即库文件)的时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径,此时就需要系统动态载入器 (dynamic linker/loader) 
        对于 elf 格式的可执行程序,是由 ld-linux.so* 来完成的,它先后搜索 elf 文件的 DT_RPATH 段-->环境变量LD_LIBRARY_PATH—->/etc/ld.so.cache 文件列表--> /lib/,/usr/lib 目录找到库文件后将其载入内存
        如: export LD_LIBRARY_PATH=’pwd’ 
        将当前文件目录添加为共享目录。
     
    1.6、使用ldd工具,查看可执行程序依赖那些动态库或着动态库依赖于那些动态库
       ldd 命令可以查看一个可执行程序依赖的共享库, 
        例如 # ldd /bin/lnlibc.so.6 
            => /lib/libc.so.6 (0×40021000)/lib/ld-linux.so.2 
            => /lib/ld- linux.so.2 (0×40000000) 
       可以看到 ln 命令依赖于 libc 库和 ld-linux 库 
     
    1.7、使用nm工具,查看静态库动态库有那些函数名;
        T类表示函数是当前库中定义的U类表示函数是被调用的,在其它库中定义的W类当前库中定义,被其它库中的函数覆盖)。
        有时候可能需要查看一个库中到底有哪些函数,nm工具可以打印出库中的涉及到的所有符号,这里的库既可以是静态的也可以是动态的。

    nm列出的符号有很多, 常见的有三种::

    T类:库中定义的函数,用T表示,这是最常见的

    U类:在库中被调用,但并没有在库中定义(表明需要其他库支持),用U表示

    W类:是所谓的“弱态”符号,它们虽然在库中被定义,但是可能被其他库中的同名符号覆盖,用W表示

    例如,假设开发者希望知道上文提到的hello库中是否引用了 printf():

       nm libhello.so | grep printf 

    发现printf是U类符号,说明printf被引用,但是并没有在库中定义。

    由此可以推断,要正常使用hello库,必须有其它库支持,使用ldd工具查看hello依赖于哪些库:

    ldd libhello.so

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

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

    从上面的结果可以继续查看printf最终在哪里被定义,有兴趣可以go on

    1.8、使用ar工具,可以生成静态库,同时可以查看静态库中包含那些.o文件,即有那些源文件构成

    可以使用 ar -t libname.a 来查看一个静态库由那些.o文件构成。

    可以使用 ar q libname.a xxx1.o xxx2.o xxx3.o ... xxxn.o 生成静态库

    1.9、如何查看动态库和静态库是32位,还是64位下的库:

    如果是动态库,可以使用file *.so;

    如果是静态哭,可以使用objdump -x *.a

    Linux下进行程序设计时,关于库的使用:
    一、gcc/g++命令中关于库的参数:
        -shared: 该选项指定生成动态连接库;
        -fPIC:表示编译为位置独立(地址无关)的代码,不用此选项的话,编译后的代码是位置相关的,所以动态载入时,是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
        -L:指定链接库的路径,-L. 表示要连接的库在当前目录中
        -ltest:指定链接库的名称为test,编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称
        -Wl,-rpath: 记录以来so文件的路径信息。
        LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。
         当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来达到同样的目的,
         不过如果没有root权限,那么只能采用修改LD_LIBRARY_PATH环境变量的方法了。 
    调用动态库的时候,有几个问题会经常碰到:
        1、有时,明明已经将库的头文件所在目录 通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so文件,这时你要作的就是通过修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录。通常这样做就可以解决库无法链接的问题了。
     
    二、静态库链接时搜索路径的顺序: 
       1. ld会去找gcc/g++命令中的参数-L;
       2. 再找gcc的环境变量LIBRARY_PATH,它指定程序静态链接库文件搜索路径;
          export LIBRARY_PATH=$LIBRARY_PATH:data/home/billchen/lib 
       3. 再找默认库目录 /lib  /usr/lib  /usr/local/lib,这是当初compile gcc时写在程序内的。 
       
    三、动态链接时、执行时搜索路径顺序: 
        1. 编译目标代码时指定的动态库搜索路径;
        2. 环境变量LD_LIBRARY_PATH指定动态库搜索路径,它指定程序动态链接库文件搜索路径;
          export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:data/home/billchen/lib 
        3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径;
        4. 默认的动态库搜索路径/lib;
        5. 默认的动态库搜索路径/usr/lib。 
     
    四、静态库和动态链接库同时存在时,gcc/g++默认链接的是动态库:
        当一个库同时存在静态库和动态库时,比如libmysqlclient.a和libmysqlclient.so同时存在时:
        在Linux下,动态库和静态库同事存在时,gcc/g++的链接程序,默认链接的动态库
    
        可以使用下面的方法,给连接器ld传递参数,看是否链接动态库还是静态库。
    
        -Wl,-Bstatic -llibname        //指定让gcc/g++链接静态库
        使用:
        gcc/g++ test.c -o test -Wl,-Bstatic -llibname -Wl,-Bdynamic -lm -lc 
    
        -Wl,-Bdynamic -llibname       //指定让gcc/g++链接动态库
        使用:
        gcc/g++ test.c -o test -Wl,-Bdynamic -llibname
       如果要完全静态加在,使用-static参数,即将所有的库以静态的方式链入可执行程序,这样生成的可执行程序,不再依赖任何库,同事出现的问题是,这样编译出来的程序非常大,占用空间。
    如果不适用-Wl,-Bdynamic -lm -c会有如下错误:
    [chenbaihu@build17 lib]$ ls
    libtest.a  libtest.so  t  t.cc  test.cc  test.h  test.o
    [chenbaihu@build17 lib]$ g++ -Wall -g t.cc -o t -L./ -Wl,-Bstatic -ltest -Wl,-Bdynamic -lm -lc
    [chenbaihu@build17 lib]$ g++ -Wall -g t.cc -o t -L./ -Wl,-Bstatic -ltest 
    /usr/bin/ld: cannot find -lm
    collect2: ld 返回 1
    参考:
         http://lists.gnu.org/archive/html/help-gnu-utils/2004-03/msg00009.html
    五、有关环境变量: 
        LIBRARY_PATH环境变量:指定程序静态链接库文件搜索路径
        LD_LIBRARY_PATH环境变量:指定程序动态链接库文件搜索路径 
     
    六、库的依赖问题:
       比如我们有一个基础库libbase.a,还有一个依赖libbase.a编译的库,叫做libchild.a;在我们编译程序时,一定要先-lchild再-lbase。 如果使用 -lbase -lchild,在编译时将出现一些函数undefined,而这些函数实际上已经在base中已经定义;
       为什么会有库的依赖问题?
       一、静态库解析符号引用:
          链接器ld是如何使用静态库来解析引用的。在符号解析阶段,链接器从左至右,依次扫描可重定位目标文件(*.o)静态库(*.a)在这个过程中,链接器将维持三个集合:
       集合E:可重定位目标文件(*.o文件)的集合。
       集合U:未解析(未定义)的符号集,即符号表中UNDEF的符号。
       集合D: 已定义的符号集。
       初始情况下,E、U、D均为空。
       1、对于每个输入文件f,如果是目标文件(.o),则将f加入E,并用f中的符号表修改U、D(在文件f中定义实现的符号是D,在f中引用的符号是U),然后继续下个文件。
       2、如果f是一个静态库(.a),那么链接器将尝试匹配U中未解析符号与静态库成员(静态库的成员就是.o文件)定义的符号。如果静态库中某个成员m(某个.o文件)定义了一个符号来解析U中引用,那么将m加入E中,
       同时使用m的符号表,来更新U、D。对静态库中所有成员目标文件反复进行该过程,直至U和D不再发生变化。此时,静态库f中任何不包含在E中的成员目标文件都将丢弃,链接器将继续下一个文件。
       3、当所有输入文件完成后,如果U非空,链接器则会报错,否则合并和重定位E中目标文件,构建出可执行文件。
     到这里,为什么会有库的依赖问题已经得到解答:
     因为libchild.a依赖于libbase.a,但是libbase.a在libchild.a的左边,导致libbase.a中的目标文件(*.o)根本就没有被加载到E中,所以解决方法就是交换两者的顺序。当然也可以使用-lbase -lchild -lbase的方法。
    参考文章:http://pananq.com/index.php/page/3/
     
    七、动态库升级问题:
       在动态链接库升级时,
       不能使用cp newlib.so oldlib.so,这样有可能会使程序core掉;
       而应该使用:
       rm oldlib.so 然后 cp newlib.so oldlib.so
       或者
        mv oldlib.so oldlib.so_bak 然后 cp newlib.so oldlib.so
    

    为什么不能用cp newlib.so oldlib.so ?

    在替换so文件时,如果在不停程序的情况下,直接用 cp new.so old.so 的方式替换程序使用的动态库文件会导致正在运行中的程序崩溃。

    解决方法:

    解决的办法是采用“rm+cp” 或“mv+cp” 来替代直接“cp” 的操作方法。

    linux系统的动态库有两种使用方法:运行时动态链接库,动态加载库并在程序控制之下使用。

    1、为什么在不停程序的情况下,直接用 cp 命令替换程序使用的 so 文件,会使程序崩溃? 很多同学在工作中遇到过这样一个问题,在替换 so 文件时,如果在不停程序的情况下,直接用cp new.so old.so的方式替换程序使用的动态库文件会导致正在运行中的程序崩溃,退出。

    这与 cp 命令的实现有关,cp 并不改变目标文件的 inode,cp 的目标文件会继承被覆盖文件的属性而非源文件。实际上它是这样实现的: strace cp libnew.so libold.so 2>&1 |grep open.*lib.*.so open("libnew.so", O_RDONLY|O_LARGEFILE) = 3 open("libold.so", O_WRONLY|O_TRUNC|O_LARGEFILE) = 4 在 cp 使用“O_WRONLY|O_TRUNC” 打开目标文件时,原 so 文件的镜像被意外的破坏了。这样动态链接器 ld.so 不能访问到 so 文件中的函数入口。从而导致 Segmentation fault,程序崩溃。ld.so 加载 so 文件及“再定位”的机制比较复杂。

    2、怎样在不停止程序的情况下替换so文件,并且保证程序不会崩溃? 答案是采用“rm+cp” 或“mv+cp” 来替代直接“cp” 的操作方法。

    在用新的so文件 libnew.so 替换旧的so文件 libold.so 时,如果采用如下方法: rm libold.so //如果内核正在使用libold.so,那么inode节点不会立刻别删除掉。 cp libnew.so libold.so 采用这种方法,目标文件 libold.so 的 inode 其实已经改变了,原来的 libold.so 文件虽然不能用"ls"查看到,但其inode并没有被真正删除,直到内核释放对它的引用。

    (即: rm libold.so,此时,如果ld.so正在加在libold.so,内核就在引用libold.so的inode节点,rm libold.so的inode并没有被真正删除,当ld.so对libold.so的引用结束,inode才会真正删除。这样程序就不会崩溃,因为它还在使用旧的libold.so,当下次再使用libold.so时,已经被替换,就会使用新的libold.so)

    同理,mv只是改变了文件名,其 inode 不变,新文件使用了新的 inode。这样动态链接器 ld.so 仍然使用原来文件的 inode 访问旧的 so 文件。因而程序依然能正常运行。

    (即: mv libold.so ***后,如果程序使用动态库,还是使用旧的inode节点,当下次再使用libold.so时,就会使用新的libold.so)

    到这里,为什么直接使用“cp new_exec_file old_exec_file”这样的命令时,系统会禁止这样的操作,并且给出这样的提示“cp: cannot create regular file `old': Text file busy”。

    这时,我们采用的办法仍然是用“rm+cp”或者“mv+cp”来替代直接“cp”,这跟以上提到的so文件的替换有同样的道理

    但是,为什么系统会阻止cp覆盖可执行程序,而不阻止覆盖so文件

    这是因为 Linux 有个 Demand Paging 机制,所谓“Demand Paging”,简单的说,就是系统为了节约物理内存开销,并不会程序运行时就将所有页(page)都加载到内存中,而只有在系统有访问需求时才将其加载。“Demand Paging”要求正在运行中的程序镜像注意,并非文件本身不被意外修改因此内核在启动程序后会锁定这个程序镜像的 inode

    对于 so 文件,它是靠 ld.so 加载的,而ld.so毕竟也是用户态程序,没有权利去锁定inode,也不应与内核的文件系统底层实现耦合。

    转自:http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520101023104745738/

    展开全文
  • linux动态库和静态库

    2015-12-27 20:22:06
    Linux下静态库_库基本概念;如何生成静态库动态库;nm查看包含那些函数、ar生成静态库,查看包含那些.o文件、ldd查看程序依赖.so文件;gcc/g++与库相关参数-L,-l,-fPIC,-shared;静态库链接时
  • 问5:如何查看 静态库(.a) ? 还有其他库文件 比如动态...在Linux 经常需要链接一些 *.a库文件,那怎么查看这些*.a 包 含哪些文件、函数、变量:  1. 查看文件:ar -t *.a  2. 查看函数、变量:nm *.a
  • linux动态库与静态库编译与加载

    千次阅读 2015-08-24 09:16:51
    Linux下静态库_库基本概念;如何生成静态库动态库;nm查看包含那些函数、ar生成静态库,查看包含那些.o文件、ldd查看程序依赖.so文件;gcc/g++与库相关参数-L,-l,-fPIC,-shared;
  • 关于linux下库的知识

    2014-01-06 09:20:54
      Linux下静态库_库基本概念;如何生成静态库动态库;nm查看包含那些函数、ar生成静态库,查看包含那些.o文件、ldd查看程序依赖.so文件;gcc/g++与库相关参数-L,-l,-fPIC,-shared;静态
  • 动态链接库的路径及依赖

    千次阅读 2014-12-22 10:03:25
    参考资料 [1]linux下,怎么用shell命令或脚本查看.so文件里面所有函数名 [2]linux下查看动态链接库so文件依赖相关组建 [4]linux下so动态库一些不为人知秘密() ...[8]linux下如何查看共享库so版本号
  • 静态库/动态库

    2014-07-11 09:43:51
    nm查看包含那些函数、ar生成静态库,查看包含那些.o文件、ldd查看程序依赖.so文件;gcc/g++与库相关参数-L,-l,-fPIC,-shared;静态库链接时搜索过程;动态库链接时,加载时搜索过程;动态库找不到问题;库...
  • 2014-11-18 18:45:39
    Linux下静态库_库基本概念;如何生成静态库动态库;nm查看包含那些函数、ar生成静态库,查看包含那些.o文件、ldd查看程序依赖.so文件;gcc/g++与库相关参数-L,-l,-fPIC,-shared;静态库链接时
  • 2.3.8 Makefile 中的函数.............................................. 46 2 . 4 用G D B 调试程序..................................................... 47 2 . 4 . 1编译可调试程序............................
  • 2.3.8 makefile中的函数 46 2.4 用gdb调试程序 47 2.4.1 编译可调试程序 48 2.4.2 使用gdb调试程序 49 2.4.3 gdb常用命令 52 2.4.4 其他的gdb 59 2.5 小结 60 第3章 文件系统简介 61 3.1 linux下的文件系统 ...
  • 动态库*.solinux下用c和c++编程时经常会碰到,记录一下,以便日后查看。 一、编译动态库 下面通过一个例子来说明如何操作。我们将hello.c编译成libhello.so。hello.c文件定义了一个print函数,该函数使用了可变...
  • 句,这里我们将其放到private 里,因为一般的函数都放在public 里,而变量 都放在private 里。 #ifndef WIDGET_H #define WIDGET_H #include #include "mydlg.h" //包含头文件 namespace Ui { class Widget; } ...
  • 操作系统(内存管理)

    热门讨论 2009-09-20 12:55:25
    文将对 Linux™ 程序员可以使用内存管理技术进行概述,虽然关注重点是 C 语言,但同样也适用于其他语言。文中将为您提供如何管理内存细节,然后将进一步展示如何手工管理内存,如何使用引用计数或者内存池来半...
  • swap,它还可以将它们映射到文件和文件位置,这样,读写内存将对文件中的数据进行读写。不过,在这里,我们只关心 mmap 向进程添加被映射的内存的能力。munmap() 所做的事情与 mmap() 相反。 如您所见,brk() ...
  • Deepin下如何科-学(地)上-网.md Deepin常用快捷键及其他便利操作.md Deepin使用体验、资源及问题归纳贴.md Deepin自定义右键新建文件模版.md Deepin设置开机自启动脚本问题.md AppImage打包方式、相关应用...
  • 组件化模式下如何通信 这是组件化工程模型下业务关系,业务之间将不再直接引用和依赖,而是通过“路由”这样一个中转站间接产生联系。在这个开源项目,我使用阿里开源路由框架。关于Arouter基础使用和代码...

空空如也

空空如也

1 2
收藏数 26
精华内容 10
关键字:

linux下如何查看动态库so中的函数

linux 订阅