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

$ar cqs libhello.a hello.o

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

$gcc -shared -o libhello.so.1.0 hello.o

3、库文件是如何命名的,有没有什么规范: 
在 linux 下,库文件一般放在/usr/lib和/lib下, 
静态库的名字一般为libxxxx.a,其中 xxxx 是该lib的名称;
动态库的名字一般为libxxxx.so.major.minor,xxxx 是该lib的名称,major是主版本号,minor是副版本号 
 
4、可执行程序在执行的时候如何定位共享库(动态库)文件 :
    当系统加载可执行代码(即库文件)的时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径,此时就需要系统动态载入器 (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’ 
将当前文件目录添加为共享目录
 
5、使用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 库 
 
6、使用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

7、使用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下找不到动态链接库的更多相关文章

  1. Linux下找不到动态链接库;

    目前,在做的一个程序,编译完后,运行发现报错说找不到自己编译生成的动态库文件,很尴尬;;;果断查资料解决,捎带复制一篇写的比较完善的文章, 地址:http://www.cnblogs.com/wies ...

  2. Linux下找不到动态链接库(转)

    1.生成静态库 生成静态库使用ar工具,其实ar是archive的意思 $ar cqs libhello.a hello.o 2.生成动态库 用gcc来完成,由于可能存在多个版本,因此通常指定版本号: ...

  3. 虚拟机Linux下找不到/dev/cdrom

    问题描述: 笔者欲更新一下VMwareTools,结果发现虚拟机Linux上找不到设备"/dev/cdrom",当然也就不能通过命令"mount /dev/cdrom / ...

  4. Linux下找不到so文件的解决办法

    http://www.cnblogs.com/xudong-bupt/p/3698294.html 如果使用自己手动生成的动态链接库.so文件,但是这个.so文件,没有加入库文件搜索路劲中,程序运行时 ...

  5. Linux下找出吃内存的方法总结

    Linux下查询进程占用的内存方法总结,假设现在有一个「php-cgi」的进程 ,进程id为「25282」. 现在想要查询该进程占用的内存大小.linux命令行下有很多的工具进行查看,现总结常见的几种 ...

  6. Linux 下找出超過某些容量的檔案

    找目前所在位置下,所有檔案大小超過3M的file,並列出檔名:大小 find . -type f -size +3M -exec ls -alh {} \; | awk '{print$9 " ...

  7. ubuntu或linux下找不到apache服务器配置文件httpd.conf

    原因是ubuntu中是apache2,没有httpd.conf文件,所有找不到. 我的是ubuntu14.04系统,apache2配置文件在/etc/apache2/apache2.conf中, 如果 ...

  8. linux下链接时缺少动态链接库

    1, 用ln将需要的so文件链接到/usr/lib或者/lib这两个默认的目录下边 ln -s /where/you/install/lib/*.so /usr/libsudo ldconfig 2, ...

  9. linux下添加动态链接库路径、动态库加载等方法

    linux下添加动态链接库路径的方法 2017年01月20日 10:08:17 阅读数:5596   Linux共享库路径配置 Linux下找不到共享库文件的典型现象为明明已经安装某个软包(如libn ...

随机推荐

  1. javascript 知识点坑

    1. JavaScript事件属性 event.target 当目标事件发生span里面 当目标事件发生在main里面 e.target; // 目标节点DOM结构   e.target.id; // ...

  2. js字符串转json

    1,eval方式解析,这是最早的解析方式了.如下: 代码如下: function strToJson(str){ var json = eval('(' + str + ')'); return js ...

  3. 使用VS Code开发TypeScript--定义变量推荐使用let

    使用VS Code开发TypeScript--定义变量推荐使用let 目录 作用域规则 JavaScript的严格模式 let与var的区别 作用域规则 一直以来我们都是通过var关键字定义JavaS ...

  4. 设置Chrome和IE搜索栏的默认搜索引擎

    由于本人比较喜欢用Google香港作为自己的默认搜索引擎,Chrome里面可以轻松设置. ======================== Chrome ======================= ...

  5. 树形dp入门

    poj2057 某公司的上下级关系是一颗树状结构,每个人不能与他的上司同时出现,每个人有一个值,求最大值. 这个题需要注意的是如果不保存状态会超时,这似乎也是大部分dp应该注意的事情啊 #includ ...

  6. 指针 v.s. 引用

    对C++的指针总觉得和引用差不多,其实还是挺有差别的. 程序 先看一个小程序: ; int& ra = a; int* pa = &ra; printf("&a = ...

  7. 数学函数类方法的使用.java

    public class Test { public static void main(String[] args) { double a=2,b=3; double z1=Math.pow(a,b) ...

  8. POJ1850 组合数学

    POJ1850 问题重述: 用26个小写字母进行编码,编码规则如下: 1)每个编码中前一个字母必须小于后一个字母 2)编码按照长度从小到大排列,相同长度按字典序进行排列 输入一个字母串,求解该编码对应 ...

  9. PHP 汉字转拼音(首拼音,所有拼音)

    <?php /** +------------------------------------------------------ * PHP 汉字转拼音 +------------------ ...

  10. php对象中类的继承性访问类型控制

    类型的访问控制通过使用修饰符允许开发人员对类中成员的访问进行限制.这是PHP5的新特性,也是OOP语言中的重要特性,大多数OOP语言都已支持此特性.PHP5支持如下三种访问修饰符,在类的封装中我们已经 ...