当前位置:C++技术网 > 资讯 > Linux编程:6 系统运行程序并不会默认从当前路径加载动态库so文件

Linux编程:6 系统运行程序并不会默认从当前路径加载动态库so文件

更新时间:2017-01-12 09:45:52浏览次数:1+次

   现在开始往Linux方向发展,所以,也开始更多分享Linux方面的使用和编程的知识。我同事是Linux大神,近水楼台,可以吸收学习不少经验。学习到了就分享出来,供更多Linux小白学习,我也是小白,哈哈哈。我重点是对比Windows来理解Linux,方便Windows程序员比较容易适应Linux。    说实话,一开始做Linux,我整个人都是蒙的。代码在哪里写,代码写好放在哪里,在哪里编译,如何链接,如何运行,makefile是什么,各种问题,汹涌而至,直接懵逼了。
    然后又要对接Python,在Windows下已经搞定了,而到Linux下,编译都成了问题,问题就出在Linux不熟悉,Linux编程也不熟悉。今天就遇到这个程序运行找不到动态库的问题,总结一下,分享给大家。
    我这里就不说如何生成动态库,如何编程调用动态库,等我琢磨透了,再来分享,以免误导。我不琢磨透可能也说不清楚,不能深入浅出,说了等于白说。
    我先在一个文件夹下test生成了一个so的动态库文件,相对于Windows就是dll文件。然后再写了一个测试程序(含main的代码)文件,编译成一个可执行程序。然后链接动态库。生成好可执行文件m(Linux中不依赖后缀名,这里我没有加后缀名,m文件就是可执行文件)后,动态库so文件和可执行文件m在同一个目录下,然后执行可执行文件,问题来了,提示:
./m: error while loading shared libraries: libcac.so: cannot open shared object file: No such file or directory
    翻译:./m:在加载共享库(动态链接库)libcac.so的时候发生错误:无法打开动态链接库文件:没有这样的文件或者目录。
    是不是傻眼了。这是按照人家的文章来做的,仔细比对了好几遍命令,没有错误。但是就是有问题。是不是很奇怪。然后就向大神请教了。下面就是得到的经验。
    在Windows中,可执行程序在运行时,加载动态链接库时,会在系统目录、环境变量指定的目录和当前可执行文件所在的目录里寻找动态链接库。然而,Linux并不会在当前可执行文件所在的目录里寻找动态链接库。所以才找不到动态链接库。你再看错误提示,是不是就理解了。
    这个问题就在于,我们对Linux的工作机制并不熟悉,相信这里是广大Linux新手小白经常会遇到的,特别是自学的,没有人告诉你,真心不知道。
    那么当前目录如何查看?如何解决找不到动态链接库的问题呢?
    因为Linux系统会在系统库目录里和环境变量的路径里查找,所以你懂的。你可以将你的动态链接库放在系统目录里或者环境变量指定的搜索路径的文件夹里。好比在Windows中的系统目录system32,然后就是Path里设置的目录。
    我们这里只要知道Linux系统目录的库文件所在的目录即可,一般是/lib、/usr/local/lib。你可以把你的动态库放在这两个目录里。不过这个不推荐。
    那么我们可以放在环境变量指定的搜索路径里咯。如何查看Linux系统的环境变量路径呢?Windows中在“我的电脑”,右击属性,然后高级,然后环境变量,就可以找到“系统环境变量”的Path的一条。而Linux可以很简单,直接打env命令,就可以打印所有的环境变量。当然也就包含了PATH。不过Linux运行时加载动态库的环境变量名称为LD_LIBRARY_PATH。运行时搜索动态库的路径的顺序参见《Linux编程GCC编译简单快速入门:链接程序库》。
    因为程序运行时会在LD_LIBRARY_PATH变量指定的路径里查找动态库。我们不推荐将自己的动态库放在系统的动态库目录里,自然我们放在LD_LIBRARY_PATH变量指定的路径的目录里是最好的,而且这个变量的值我们可以修改。这样程序在运行的时候,就不依赖系统库目录了,我们不需要事先将库文件复制到库目录里。
    那么LD_LIBRARY_PATH变量的值如何查看呢?LD_LIBRARY_PATH变量又如何设置呢?
查看LD_LIBRARY_PATH变量的值:
echo $LD_LIBRARY_PATH
    以上命令就可以打印出来LD_LIBRARY_PATH变量的值。一般情况是空的。而我们一般会将动态库放在可执行程序所在的目录下,或者相对于可执行文件所在的目录的一个子目录。可执行文件运行的时候,它所在的目录也就是当前工作目录了。我们可以查看一下当前工作目录(Current Working Dirctory),对应于Linux的命令就是pwd,英文全称为Print Working Dirctory,打印工作目录,也就是显示当前工作目录是什么。我们将目录切换到库文件所在的目录,然后pwd命令查看完整的路径。
    我们就可以将库文件目录所在的目录(即可执行文件所在的目录)设置到LD_LIBRARY_PATH变量中:
export LD_LIBRARY_PATH=/root/codexia/  
    这样我们就将LD_LIBRARY_PATH变量值设置为了/root/codexia/。只要当前用户不退出Linux系统,这个设置就会保持有效,一旦退出了Linux系统,那么这个变量的值就没有了。也就是说,LD_LIBRARY_PATH变量只对当前用户本次登录起作用。所以如果想程序每次都正常加载动态库,我们可以写一个Shell脚本,然后预先设置好LD_LIBRARY_PATH变量值,然后启动可执行文件。
    上面设置LD_LIBRARY_PATH需要注意的是,LD_LIBRARY_PATH要紧跟着=,=后面要紧跟着路径,即=号左右两侧不能有空格。我们上面是手动填写的路径,如果你移动了程序所在的目录,那么这个设置也就失效了。所以,我们可以使用自动获取当前工作目录的方式实现。我们要使用Shell的变量:
export LD_LIBRARY_PATH=${pwd}
    这样的话,这条命令会自动事先执行pwd命令,然后将输出结果填在=后面。这样你移动了文件位置,也是可以的,更加灵活。