精华内容
下载资源
问答
  • linux指定动态库路径包括:1.指定编译时动态库路径;2.指定运行时动态库路径。后文提到的动态库路径都是指的是这两种路径。众所周知,Linux动态库的默认搜索路径是/lib和/usr/lib(不管是编译还是运行都会默认搜索这...

    动态库的两种路径

    linux指定动态库路径包括:1.指定编译时动态库路径;2.指定运行时动态库路径。后文提到的动态库路径都是指的是这两种路径。众所周知,Linux动态库的默认搜索路径是/lib和/usr/lib(不管是编译还是运行都会默认搜索这两个路径)。动态库被创建后,一般都复制到这两个目录中。当程序执行时需要某动态库,并且该动态库还未加载到内存中,则系统会自动到这两个默认搜索路径中去查找相应的动态库文件,然后加载该文件到内存中,这样程序就可以使用该动态库中的函数,以及该动态库的其它资源了。

    指定动态库路径的三种方式

    在Linux 中,动态库的搜索路径除了默认的搜索路径外,还可以通过以下三种方法来指定。

    1.在配置文件/etc/ld.so.conf中指定动态库搜索路径。

    可以通过编辑配置文件/etc/ld.so.conf来指定动态库的搜索路径,该文件中每行是一个动态库搜索路径。每次编辑完该文件后,都必须运行命令ldconfig使修改后的配置生效

    以动态库的创建与使用为例:

    //so_test.h
    #include "stdio.h"
    
    void test_a();
    void test_b();
    void test_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");
    }

    测试程序

    //test.c
    #include “so_test.h”
    
    int main()
    {
        test_a();
        test_b();
        test_c();
        return 0;
    }

    操作过程:
    我们通过以下命令用源程序test_a.c、test_b.c、test_c.c来创建动态库 libtest.so。

    # gcc -c test_a.c test_b.c test_c.c
    # gcc -shared -fPIC -o libtest.so *.o
    
    或者直接一条指令:
    #gcc -shared -fPIC -o libtest.so test_a.c test_b.c test_c.c

    这样在当前目录下就生成了动态库libtest.so。对于头文件位置的存放请参考博文《linux头文件》。

    注意:
    -fPIC参数声明链接库的代码段是可以共享的(https://blog.csdn.net/u011285208/article/details/103070486);
    -shared参数声明编译为共享库。

    请注意这次我们编译的共享库的名字叫做libtest.so,这也是Linux共享库的一个命名的惯例了:后缀使用so,而名称使用libxxxx格式。

    接着通过以下命令编译test.c,生成目标程序main。

    # gcc -o main -L. –ltest test.c

    当应用程序调用动态库的时候,要用-l选项,指定所调用的库名。用-L选项指定库所在的路径(如果没有使用后文所述的三种方法处理的情况下,用这种方式指定库所在路径)。

    (注意:此时,头文件以及库文件都在当前目录下)

    在当前目录下生成可执行文件main

    运行程序main

    #./main
    
    ./main: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory

    出错了,系统未找到动态链接库libtest.so。原因是系统会默认的到/lib或/usr/lib中寻找需要的库,但是我们需要的库放在了当前的目录下,也就说虽然编译的时候指定了所需要的动态库,但是执行的时候并不会到之前编译时指定的动态库的位置去寻找动态库,这也就是为什么在文章开头讲清楚,什么是指定编译时动态库路径,什么是指定运行时动态库路径。

    解决的方法就是找到动态库。怎样找到动态库呢?最简单的解决的方法是将动态库拷贝到/lib或/usr/lib目录下,这样在编译时不需要指定动态库的路径,运行时也不会找不到动态库(不管编译还是执行都会到/lib或/usr/lib目录下寻找动态库)。对于编译阶段找到动态库的方法还有上面的通过-L选项指定动态库的路径。对于执行阶段是否可以通过选项指定动态库,下面的方法3会有介绍。

    除了上面提到的方法外,我们更需要这样一种解决思路:我们可以灵活的指定动态库的存放的位置,然后由操作系统负责动态库的查找。当然强大的linux提供了这样的功能,并且这种功能的实现不止一种,详细内容可以参考博文《/etc/ld.so.conf文件》。

    现在简单介绍/etc/ld.so.conf的使用,我们打算将制作好的动态库放在/root/lib目录下,因此执行如下命令:

    # mkdir /root/lib
    # mv libtest.so /root/lib/libtest.so

    最后编辑配置文件/etc/ld.so.conf,在该文件中追加一行/root/lib。

    运行程序main

    # ./main
    ./main: error while loading shared libraries: lib_test.so: cannot open shared object file: No such file or directory

    仍然出错,系统未找到动态库libtest.so。找找原因,原来在编辑完配置文件/etc/ld.so.conf后,没有运行命令ldconfig,所以刚才的修改还未生效。我们运行ldconfig后再试试。

    # ldconfig
    # ./main
    this is in test_a...
    this is in test_b...
    this is in test_c...
    #

    程序main运行成功,并且打印出正确结果。

    2.通过环境变量LD_LIBRARY_PATH指定动态库搜索路径。

    通过设定环境变量LD_LIBRARY_PATH也可以指定动态库搜索路径。当通过该环境变量指定多个动态库搜索路径时,路径之间用冒号”:”分隔。下面通过例2来说明本方法。

    举一个例子:
    这次我们把上面得到的文件lib_test.so移动到另一个地方去,如/root下面,然后设置环境变量LD_LIBRARY_PATH找到libtest.so。设置环境变量方法如下:

    # export LD_LIBRARY_PATH=/root
    #

    然后运行:

    #./main.out
    this is in test_a...
    this is in test_b...
    this is in test_c...
    #

    注意:设置环境变量LD_LIBRARY_PATH=/root是不行的,非得export才行。这种设置LD_LIBRARY_PATH环境变量只是临时性的,下次开启LD_LIBRARY_PATH的值会失效,因此可以将环境变量写入到/etc/bash.bashrc文件中

    3.在编译目标代码时指定该程序运行时的动态库搜索路径

    还可以在编译目标代码时指定程序的动态库搜索路径。

    -Wl,表示后面的参数将传给link程序ld(因为gcc可能会自动调用ld)。这里通过gcc 的参数”-Wl,-rpath,”指定
    举一个例子:
    这次我们还把上面得到的文件libtest.so移动到另一个地方去,如/root/test/lib下面,
    因为我们需要在编译目标代码时指定可执行文件的动态库搜索路径,所以需要用gcc命令重新编译源程序test.c来生成可执行文件main。

    # gcc -o main -L. –ltest -Wl,-rpath=/root/test/lib test.c
    #

    运行结果:

    # ./main.out
    this is in test_a...
    this is in test_b...
    this is in test_c...
    #

    程序./main运行成功。因此程序main搜索到的动态库是/root/test/lib/lib_test.so。

    关于-Wl,rpath的使用方法我再举一个例子,应该不难从中看出指定多个路径的方法:

    gcc -Wl,-rpath,/home/arc/test,-rpath,/lib/,-rpath,/usr/lib/,-rpath,/usr/local/lib test.c

    以上介绍了三种指定动态库搜索路径的方法,加上默认的动态库搜索路径/lib和/usr/lib,共五种动态库的搜索路径,那么它们搜索的先后顺序是什么呢?读者可以用下面的方法来试验一下:
    (1) 用前面介绍的方法生成5个libtest.so放在5个不同的文件夹下面,要求每一个libtest.so都唯一对应一个搜索路径,并注意main程序输出的不同。
    (2) 运行main,即可看出他是那个搜索路径下的,然后删除这个路径下的libtest.so,然后再运行。依此类推操作,即可推出搜索顺序。

    可以得出动态库的搜索路径搜索的先后顺序是:

    1.编译目标代码时指定的动态库搜索路径;

    2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径;

    3.配置文件/etc/ld.so.conf中指定的动态库搜索路径;

    4.默认的动态库搜索路径/lib;

    5.默认的动态库搜索路径/usr/lib。

    在上述1、2、3指定动态库搜索路径时,都可指定多个动态库搜索路径,其搜索的先后顺序是按指定路径的先后顺序搜索的。有兴趣的读者自己验证。

    “symbol lookup error”错误

    如果将自己的动态库放置在非默认路径,而且自己未指定搜索路径时,会在默认路径下搜索。这时候如果默认路径下有同名动态库,那么就不会报错“cannot open shared object file”,但由于两个动态库只是同名而不是完全一致,会出现“symbol lookup error”错误,使用ldd命令可以看到程序连接的是哪个动态库。

    [root@localhost ]# ./test_rcgs 
    ./test_rcgs: symbol lookup error: /root/DI/phantom/Nf_Phantom_DI_20140506_4200/lib/libdi_file_recogniser.so: undefined symbol: clist_new
    [root@localhost ]# ldd ./test_rcgs
            linux-gate.so.1 =>  (0x00611000)
            libdi_file_recogniser.so => /root/DI/phantom/Nf_Phantom_DI_20140506_4200/lib/libdi_file_recogniser.so (0x003b3000)
            libc.so.6 => /lib/libc.so.6 (0x00110000)
            /lib/ld-linux.so.2 (0x0037a000)
    
    [root@localhost ]#  export LD_LIBRARY_PATH=./lib/
    [root@localhost ]# echo $LD_LIBRARY_PATH
    ./lib/
    [root@localhost ]# ldd test_rcgs 
            linux-gate.so.1 =>  (0x007b4000)
            libdi_file_recogniser.so => ./lib/libdi_file_recogniser.so (0x00d6c000)
            libc.so.6 => /lib/libc.so.6 (0x0039d000)
            /lib/ld-linux.so.2 (0x0037a000)
    展开全文
  • 不同版本的动态库可能会不兼容,如果程序在编译指定动态库是某个低版本,运行是用的一个高版本,可能会导致无法运行。Linux上对动态库的命名采用libxxx.so.a.b.c的格式,其中a代表大版本号,b代表小版本号,c代表...
  • Linux指定动态库路径

    千次阅读 2018-02-01 10:07:56
    Linux指定动态库路径 http://blog.csdn.net/weicao1990/article/details/51028335 linux指定动态库路径包括:1.指定编译时动态库路径;2.指定运行时动态库路径。后文提到的动态库路径都是指的是这两种...

    本文转自:

    Linux指定动态库路径

    http://blog.csdn.net/weicao1990/article/details/51028335


    linux指定动态库路径包括:1.指定编译时动态库路径;2.指定运行时动态库路径。后文提到的动态库路径都是指的是这两种路径。众所周知,Linux动态库的默认搜索路径是/lib和/usr/lib(不管是编译还是运行都会默认搜索这两个路径)。动态库被创建后,一般都复制到这两个目录中。当程序执行时需要某动态库,并且该动态库还未加载到内存中,则系统会自动到这两个默认搜索路径中去查找相应的动态库文件,然后加载该文件到内存中,这样程序就可以使用该动态库中的函数,以及该动态库的其它资源了。

    在Linux 中,动态库的搜索路径除了默认的搜索路径外,还可以通过以下三种方法来指定。

    1.在配置文件/etc/ld.so.conf中指定动态库搜索路径。
    可以通过编辑配置文件/etc/ld.so.conf来指定动态库的搜索路径,该文件中每行一个动态库搜索路径。每次编辑完该文件后,都必须运行命令ldconfig使修改后的配置生效。

    以动态库的创建与使用为

    //so_test.h

    #include "stdio.h"

    void test_a();

    void test_b();

    void test_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");

    }

    测试程序

    //test.c

    #include “so_test.h”

    int main()

    {

        test_a();

        test_b();

        test_c();

        return 0;

    }

    操作过程:
    我们通过以下命令用源程序test_a.c、test_b.c、test_c.c来创建动态库 libtest.so。
    # gcc -c test_a.c test_b.c test_c.c
    # gcc -shared -fPIC -o libtest.so *.o
    或者直接一条指令:
    #gcc -shared -fPIC -o libtest.so test_a.c test_b.c test_c.c

    这样在当前目录下就生成了动态库libtest.so。对于头文件位置的存放请参考博文《linux头文件》。

    注意:
    -fPIC参数声明链接库的代码段是可以共享的
    -shared参数声明编译为共享库

    请注意这次我们编译的共享库的名字叫做libtest.so,这也是Linux共享库的一个命名的惯例了:后缀使用so,而名称使用libxxxx格式。

    接着通过以下命令编译test.c,生成目标程序main。
    # gcc -o main -L. –ltest test.c

    当应用程序调用动态库的时候,要用-l选项,指定所调用的库名。用-L选项指定库所在的路径(如果没有使用后文所述的三种方法处理的情况下,用这种方式指定库所在路径)。

    (注意:此时,头文件以及库文件都在当前目录下)

    在当前目录下生成可执行文件main

    运行程序main

    #./main

    ./main: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory

    出错了,系统未找到动态链接库libtest.so。原因是系统会默认的到/lib或/usr/lib中寻找需要的库,但是我们需要的库放在了当前的目录下,也就说虽然编译的时候指定了所需要的动态库,但是执行的时候并不会到之前编译时指定的动态库的位置去寻找动态库,这也就是为什么在文章开头讲清楚,什么是指定编译时动态库路径,什么是指定运行时动态库路径。解决的方法就是找到动态库。怎样找到动态库呢?最简单的解决的方法是将动态库拷贝到/lib或/usr/lib目录下,这样在编译时不需要指定动态库的路径,运行时也不会找不到动态库(不管编译还是执行都会到/lib或/usr/lib目录下寻找动态库)。对于编译阶段找到动态库的方法还有上面的通过-L选项指定动态库的路径。对于执行阶段是否可以通过选项指定动态库,下面的方法3会有介绍。除了上面提到的方法外,我们更需要这样一种解决思路:我们可以灵活的指定动态库的存放的位置,然后由操作系统负责动态库的查找。当然强大的linux提供了这样的功能,并且这种功能的实现不止一种,详细内容可以参考博文《/etc/ld.so.conf文件》。现在简单介绍/etc/ld.so.conf的使用,我们打算将制作好的动态库放在/root/lib目录下,因此执行如下命令:
    # mkdir /root/lib
    # mv libtest.so /root/lib/libtest.so

    最后编辑配置文件/etc/ld.so.conf,在该文件中追加一行/root/lib。

    运行程序main
    # ./main
    ./main: error while loading shared libraries: lib_test.so: cannot open shared object file: No such file or directory
    仍然出错,系统未找到动态库libtest.so。找找原因,原来在编辑完配置文件/etc/ld.so.conf后,没有运行命令ldconfig,所以刚才的修改还未生效。我们运行ldconfig后再试试。

    # ldconfig
    # ./main
    this is in test_a...

    this is in test_b...

    this is in test_c...
    #
    程序main运行成功,并且打印出正确结果。

    2.通过环境变量LD_LIBRARY_PATH指定动态库搜索路径。
    通过设定环境变量LD_LIBRARY_PATH也可以指定动态库搜索路径。当通过该环境变量指定多个动态库搜索路径时,路径之间用冒号”:”分隔。下面通过例2来说明本方法。

    举一个例子:
    这次我们把上面得到的文件lib_test.so移动到另一个地方去,如/root下面,然后设置环境变量LD_LIBRARY_PATH找到libtest.so。设置环境变量方法如下:
    # export LD_LIBRARY_PATH=/root
    #
    然后运行:
    #./main.out
    this is in test_a...

    this is in test_b...

    this is in test_c...
    #
    注意:设置环境变量LD_LIBRARY_PATH=/root是不行的,非得export才行。这种设置LD_LIBRARY_PATH环境变量只是临时性的,下次开启LD_LIBRARY_PATH的值会失效,因此可以将环境变量写入到/etc/bash.bashrc文件中。

    3.在编译目标代码时指定该程序运行时的动态库搜索路径。
    还可以在编译目标代码时指定程序的动态库搜索路径。-Wl,表示后面的参数将传给link程序ld(因为gcc可能会自动调用ld)。这里通过gcc 的参数”-Wl,-rpath,”指定
    举一个例子:
    这次我们还把上面得到的文件libtest.so移动到另一个地方去,如/root/test/lib下面,
    因为我们需要在编译目标代码时指定可执行文件的动态库搜索路径,所以需要用gcc命令重新编译源程序test.c来生成可执行文件main。
    # gcc -o main -L. –ltest -Wl,-rpath=/root/test/lib test.c
    #

    运行结果:
    # ./main.out

    this is in test_a...

    this is in test_b...

    this is in test_c...
    #

    程序./main运行成功。因此程序main搜索到的动态库是/root/test/lib/lib_test.so。

    关于-Wl,rpath的使用方法我再举一个例子,应该不难从中看出指定多个路径的方法:
    gcc -Wl,-rpath,/home/arc/test,-rpath,/lib/,-rpath,/usr/lib/,-rpath,/usr/local/lib test.c

    以上介绍了三种指定动态库搜索路径的方法,加上默认的动态库搜索路径/lib和/usr/lib,共五种动态库的搜索路径,那么它们搜索的先后顺序是什么呢?读者可以用下面的方法来试验一下:
    (1) 用前面介绍的方法生成5个libtest.so放在5个不同的文件夹下面,要求每一个libtest.so都唯一对应一个搜索路径,并注意main程序输出的不同。
    (2) 运行main,即可看出他是那个搜索路径下的,然后删除这个路径下的libtest.so,然后再运行。依此类推操作,即可推出搜索顺序。

    可以得出动态库的搜索路径搜索的先后顺序是:

    1.编译目标代码时指定的动态库搜索路径;

    2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径;

    3.配置文件/etc/ld.so.conf中指定的动态库搜索路径;

    4.默认的动态库搜索路径/lib;

    5.默认的动态库搜索路径/usr/lib。

    在上述1、2、3指定动态库搜索路径时,都可指定多个动态库搜索路径,其搜索的先后顺序是按指定路径的先后顺序搜索的。有兴趣的读者自己验证。

    展开全文
  • 不同版本的动态库可能会不兼容,如果程序在编译指定动态库是某个低版本,运行是用的一个高版本,可能会导致无法运行。Linux上对动态库的命名采用libxxx.so.a.b.c的格式,其中a代表大版本号,b代表小版本号,c代表...

    不同版本的动态库可能会不兼容,如果程序在编译时指定动态库是某个低版本,运行是用的一个高版本,可能会导致无法运行。Linux上对动态库的命名采用libxxx.so.a.b.c的格式,其中a代表大版本号,b代表小版本号,c代表更小的版本号,我们以Linux自带的cp程序为例,通过ldd查看其依赖的动态库

     $ ldd /bin/cp                                                                                                                                                                                        
    linux-vdso.so.1 =>  (0x00007ffff59df000)
    libselinux.so.1 => /lib64/libselinux.so.1 (0x00007fb3357e0000)
    librt.so.1 => /lib64/librt.so.1 (0x00007fb3355d7000)
    libacl.so.1 => /lib64/libacl.so.1 (0x00007fb3353cf000)
    libattr.so.1 => /lib64/libattr.so.1 (0x00007fb3351ca000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fb334e35000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007fb334c31000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fb335a0d000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fb334a14000)
    

    左边是依赖的动态库名字,右边是链接指向的文件,再查看libacl.so相关的动态库

      $ ll /lib64/libacl.so*                                                                                                                                                                               
    lrwxrwxrwx. 1 root root    15 1月   7 2015 /lib64/libacl.so.1 -> libacl.so.1.1.0
    -rwxr-xr-x. 1 root root 31280 12月  8 2011 /lib64/libacl.so.1.1.0
    

    我们发现libacl.so.1实际上是一个软链接,它指向的文件是libacl.so.1.1.0,命名方式符合我们上面的描述。也有不按这种方式命名的,比如

    $ ll /lib64/libc.so*                                                                                                                                                                                  
    lrwxrwxrwx 1 root root 12 8月  12 14:18 /lib64/libc.so.6 -> libc-2.12.so
    

    不管怎样命名,只要按照规定的方式来生成和使用动态库,就不会有问题。而且我们往往是在机器A上编译程序,在机器B上运行程序,编译和运行的环境其实是有略微不同的。下面就说说动态库在生成和使用过程中的一些问题。

    动态库的编译

    我们以一个简单的程序作为例子

    // filename:hello.c
    #include <stdio.h>
    
    void hello(const char* name)
    {
        printf("hello %s!\n", name);
    }
    
    // filename:hello.h
    void hello(const char* name);
    

    采用如下命令进行编译

    gcc hello.c -fPIC -shared -Wl,-soname,libhello.so.0 -o libhello.so.0.0.1
    

    需要注意的参数是 -Wl,soname(中间没有空格),-Wl选项告诉编译器将后面的参数传递给链接器,
    -soname则指定了动态库的soname(简单共享名,Short for shared object name)

    现在我们生成了libhello.so.0.0.1,当我们运行 ldconfig -n . 命令时,当前目录会多一个软连接

     $ ll libhello.so.0                                                                                                                                                                                   
    lrwxrwxrwx 1 handy handy 17 8月  17 14:18 libhello.so.0 -> libhello.so.0.0.1
    

    这个软链接是如何生成的呢,并不是截取libhello.so.0.0.1名字的前面部分,而是根据libhello.so.0.0.1编译时指定的-soname生成的。也就是说我们在编译动态库时通过-soname指定的名字,已经记载到了动态库的二进制数据里面。不管程序是否按libxxx.so.a.b.c格式命名,但Linux上几乎所有动态库在编译时都指定了-soname,我们可以通过readelf工具查看soname,比如文章开头列举的两个动态库

     $ readelf -d /lib64/libacl.so.1.1.0                                                                                                                                                                   
    
    Dynamic section at offset 0x6de8 contains 24 entries:
    Tag        Type                         Name/Value
    0x0000000000000001 (NEEDED)             Shared library: [libattr.so.1]
    0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
    0x000000000000000e (SONAME)             Library soname: [libacl.so.1]
    

    这里省略了一部分,可以看到最后一行SONAME为libacl.so.1,所以/lib64才会有一个这样的软连接

    再看libc-2.12.so文件,该文件并没有采用我们说的命名方式

     $ readelf -d /lib64/libc-2.12.so                                                                                                                                                                      
    
    Dynamic section at offset 0x18db40 contains 27 entries:
    Tag        Type                         Name/Value
    0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]
    0x000000000000000e (SONAME)             Library soname: [libc.so.6]
    

    同样可以看到最后一行SONAME为libc.so.6,即便该动态库没有按版本号的方式命名,但仍旧有一个软链指向该动态库,而该软链的名字就是soname指定的名字

    所以关键就是这个soname,它相当于一个中间者,当我们的动态库只是升级一个小版本时,我们可以让它的soname相同,而可执行程序只认soname指定的动态库,这样依赖这个动态库的可执行程序不需重新编译就能使用新版动态库的特性

    可执行程序的编译

    还是以hello动态库为例,我们写一个简单的程序

    // filename:main.c
    #include "hello.h"
    
    int main()
    {
        hello("handy");
        return 0;
    }
    

    现在目录下是如下结构

    ├── hello.c
    ├── hello.h
    ├── libhello.so.0 -> libhello.so.0.0.1
    ├── libhello.so.0.0.1
    └── main.c
    

    libhello.so.0.0.1是我们编译生成的动态库,libhello.so.0是通过ldconfig生成的链接,采用如下命令编译main.c

     $ gcc main.c -L. -lhello -o main                                                                                                                                                                            
    /usr/bin/ld: cannot find -lhello
    

    报错找不到hello动态库,在Linux下,编译时指定-lhello,链接器会去寻找libhello.so这样的文件,当前目录下没有这个文件,所以报错。建立这样一个软链,目录结构如下

    ├── hello.c
    ├── hello.h
    ├── libhello.so -> libhello.so.0.0.1
    ├── libhello.so.0 -> libhello.so.0.0.1
    ├── libhello.so.0.0.1
    └── main.c
    

    让libhello.so链接指向实际的动态库文件libhello.so.0.0.1,再编译main程序

    gcc main.c -L. -lhello -o main
    

    这样可执行文件就生成了。通过以上测试我们发现,在编译可执行程序时,链接器会去找它依赖的libxxx.so这样的文件,因此必须保证libxxx.so的存在

    用ldd查看其依赖的动态库

     $ ldd main                                                                                                                                                                                            
            linux-vdso.so.1 =>  (0x00007fffe23f2000)
            libhello.so.0 => not found
            libc.so.6 => /lib64/libc.so.6 (0x00007fb6cd084000)
            /lib64/ld-linux-x86-64.so.2 (0x00007fb6cd427000)
    

    我们发现main程序依赖的动态库名字是libhello.so.0,既不是libhello.so也不是libhello.so.0.0.1。其实在生成main程序的过程有如下几步

    • 链接器通过编译命令 -L. -lhello 在当前目录查找libhello.so文件
    • 读取libhello.so链接指向的实际文件,这里是libhello.so.0.0.1
    • 读取libhello.so.0.0.1中的SONAME,这里是libhello.so.0
    • 将libhello.so.0记录到main程序的二进制数据里
    • 也就是说libhello.so.0是已经存储到main程序的二进制数据里的,不管这个程序在哪里,通过ldd查看它依赖的动态库都是libhello.so.0

    而为什么这里ldd查看main显示libhello.so.0为not found呢,因为ldd是从环境变量$LD_LIBRARY_PATH指定的路径里来查找文件的,我们指定环境变量再运行如下

     $ export LD_LIBRARY_PATH=. && ldd main                                                                                                                                                                
        linux-vdso.so.1 =>  (0x00007fff7bb63000)
        libhello.so.0 => ./libhello.so.0 (0x00007f2a3fd39000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f2a3f997000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f2a3ff3b000)
    

    可执行程序的运行

    现在测试目录结果如下

    ├── hello.c
    ├── hello.h
    ├── libhello.so -> libhello.so.0.0.1
    ├── libhello.so.0 -> libhello.so.0.0.1
    ├── libhello.so.0.0.1
    ├── main
    └── main.c
    

    这里我们把编译环境和运行环境混在一起了,不过没关系,只要我们知道其中原理,就可以将其理清楚

    前面我们已经通过ldd查看了main程序依赖的动态库,并且指定了LD_LIBRARY_PATH变量,现在就可以直接运行了

     $ ./main                                                                                                                                                                                              
    hello Handy!
    

    看起来很顺利。那么如果我们要部署运行环境,该怎么部署呢。显然,源代码是不需要的,我们只需要动态库和可执行程序。这里新建一个运行目录,并拷贝相关文件,目录结构如下

    ├── libhello.so.0.0.1
    └── main
    

    这时运行会main会发现

     $ ./main                                                                                                                                                                                              
    ./main: error while loading shared libraries: libhello.so.0: cannot open shared object file: No such file or directory
    

    报错说libhello.so.0文件找不到,也就是说 程序运行时需要寻找的动态库文件名其实是动态库编译时指定的SONAME,这也和我们用ldd查看的一致。通过 ldconfig -n . 建立链接,如下

    ├── libhello.so.0 -> libhello.so.0.0.1
    ├── libhello.so.0.0.1
    └── main
    

    再运行程序,结果就会符合预期了

    从上面的测试看出,程序在运行时并不需要知道libxxx.so,而是需要程序本身记载的该动态库的SONAME,所以main程序的运行环境只需要以上三个文件即可

    动态库版本更新

    假设动态库需要做一个小小的改动,如下

    // filename:hello.c
    #include <stdio.h>
    
    void hello(const char* name)
    {
        printf("hello %s, welcom to our world!\n", name);
    }
    

    由于改动较小,我们编译动态库时仍然指定相同的soname

    gcc hello.c -fPIC -shared -Wl,-soname,libhello.so.0 -o libhello.so.0.0.2
    

    将新的动态库拷贝到运行目录,此时运行目录结构如下

    ├── libhello.so.0 -> libhello.so.0.0.1
    ├── libhello.so.0.0.1
    ├── libhello.so.0.0.2
    └── main
    

    此时目录下有两个版本的动态库,但libhello.so.0指向的是老本版,运行 ==ldconfig -n .==后我们发现,链接指向了新版本,如下

    ├── libhello.so.0 -> libhello.so.0.0.2
    ├── libhello.so.0.0.1
    ├── libhello.so.0.0.2
    └── main
    

    再运行程序

     $ ./main                                                                                                                                                                                              
    hello Handy, welcom to our world!
    

    没有重新编译就使用上了新的动态库, wonderful!

    同样,假如我们的动态库有大的改动,编译动态库时指定了新的soname,如下

    gcc hello.c -fPIC -shared -Wl,-soname,libhello.so.1 -o libhello.so.1.0.0
    

    将动态库文件拷贝到运行目录,并执行 ldconfig -n .,目录结构如下

    ├── libhello.so.0 -> libhello.so.0.0.2
    ├── libhello.so.0.0.1
    ├── libhello.so.0.0.2
    ├── libhello.so.1 -> libhello.so.1.0.0
    ├── libhello.so.1.0.0
    └── main
    

    这时候发现,生成了新的链接libhello.so.1,而main程序还是使用的libhello.so.0,所以无法使用新版动态库的功能,需要重新编译才行

    最后

    在实际生产环境中,程序的编译和运行往往是分开的,但只要搞清楚这一系列过程中的原理,就不怕被动态库的版本搞晕。简单来说,按如下方式来做

    • 编译动态库时指定-Wl,-soname,libxxx.so.a,设置soname为libxxx.so.a,生成实际的动态库文件libxxx.so.a.b.c
    • 编译可执行程序时保证libxx.so存在,如果是软链,必须指向实际的动态库文件libxxx.so.a.b.c
    • 运行可执行文件时保证libxxx.so.a.b.c文件存在,通过ldconfig生成libxxx.so.a链接指向libxxx.so.a.b.c
    • 设置环境变量LD_LIBRARY_PATH,运行可执行程序
    展开全文
  • Linux编译动态库及使用

    万次阅读 2017-12-20 18:14:43
    linux下生成和使用动态库的步骤如下: 1,编写源文件。 2,将一个或几个源文件编译链接,生成共享库。 3,通过 -L&lt;path&gt; -lxxx 的gcc选项链接生成的libxxx.so。 4,把libxxx.so放入链接库的标准路径,或...

    说明:

    linux下生成和使用动态库的步骤如下:

    1,编写源文件。
    2,将一个或几个源文件编译链接,生成共享库。
    3,通过 -L<path> -lxxx 的gcc选项链接生成的libxxx.so。
    4,把libxxx.so放入链接库的标准路径,或指定 LD_LIBRARY_PATH,才能运行链接了libxxx.so的程序。
     

     

    一, 生成动态库

    1)test.c文件

    #include "test.h"
    
    void itoa(int *num)
    {
        if(*num>=65&&*num<=88)
        {
            *num=*num - 65+'a';
        }
    }

     

     

    2)头文件

    #ifndef __ITOA_H_
    #define __ITOA_H_
    
    extern void itoa(int *); 
    
    #endif

     


    二,编译生成动态库

     

    gcc test.c  -fPIC -shared -o libtest.so

    -o 参数指定生成libtest.so ;此为动态库,Linux下格式为libxxx.so ;xxx 是后面你要调用的库名

     

     
     

    三,使用动态库

    1)自己写个测试main.c  用来测试库中的函数

     

    2)使用gcc main.c -L. -ltest 生成a.out

    -L. :-L参数是指定库的位置,注意此处有个'.' 表示当前路径

    -l :其中-ltest表示要链接libtest.so   

     


    四,运行

    1)运行 ./a.out 会得到以下的错误提示。

    ./a.out: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory

    提示:找不到libtest.so。

     

    2)找不到库的原因

    Linux是通过 /etc/ld.so.cache 文件搜寻要链接的动态库的。

    而 /etc/ld.so.cache 是 ldconfig 程序读取 /etc/ld.so.conf 文件生成的。
    (注意, /etc/ld.so.conf 中并不必包含 /lib 和 /usr/lib,ldconfig程序会自动搜索这两个目录)

    所以把 libtest.so 所在的路径添加到 /etc/ld.so.conf 中

    再以root权限运行 ldconfig 程序更新ld.so.cache

    a.out运行时,就可以找到 libtest.so。

     

    3)使用临时解决的方法

    但作为一个简单的测试例子,让我们改动系统的东西,似乎不太合适。

    还有另一种简单的方法,就是为a.out指定 LD_LIBRARY_PATH。

     

    LD_LIBRARY_PATH=../a.out    或者  export LD_LIBRARY_PATH=.  再执行./a.out

     

    程序就能正常运行了。LD_LIBRARY_PATH=. 是告诉 a.out,先在当前路径寻找链接的动态库。

    展开全文
  • 不同版本号的动态库可能会不兼容,假设程序在编译指定动态库是某个低版本号。执行是用的一个高版本号,可能会导致无法执行。Linux上对动态库的命名採用libxxx.so.a.b.c的格式。当中a代表大版本号号。b代表小版本号...
  • Linux指定动态库的加载路径

    千次阅读 2018-09-04 10:30:28
    一、库文件的搜索路径: 1、在配置文件/etc/ld.so....2、通过环境变量LD_LIBRARY_PATH指定动态库搜索路径(当通过该环境变量指定多个动态库搜索路径时,路径之间用冒号":"分隔) 3、在编译目标代码时指...
  • 动态库的调用是动态加载的,一般需要指定动态库的位置,编译文件执行时找到 现在有三种方法解决这个问题 1. 将动态库文件放置到/usr/lib或者/lib目录下 2. 将当前动态的路径,导出环境变量 3.在配置文件中添加...
  • 动态库搜索分为两个时期:编译期和运行期。 一、编译期 1、通过-L命令指定。比如-L ./指定在当前目录下搜索动态库文件 2、在LIBRARY_PATH变量中指定 3、系统固定搜索目录:/lib、/usr/lib 二、运行期 1、编译...
  • gcc -c xxx.c -I/头文件的路径 一般是: gcc -c read.c -I/home/speex/include gcc -o read read.o -L/home/speex/lib -l/speex -L/动态库的路径 -I/动态库的名字
  • Linux 动态库编译

    2020-09-14 23:43:59
    动态库制作: 参考链接 ... 现在又 demo.c内容如下 ...-shared :指定生成动态库 -fpic:是一种标准,作用于编译选项,生成位置无关码。 使用 ls查看 2动态库的使用 直接使用:默认生成 a...
  • linux指定动态库路径

    2013-07-30 17:17:00
    linux指定动态库路径 通常有两种方法: 1.把动态库放到系统库或者在系统库中做一个链接,这样编译和运行都会去系统库找。这样容易引起系统库混乱。 2.export LD_LIBRARY_PATH=###。指定库搜索路径,...
  • linux编译动态库找不到的问题

    千次阅读 2019-03-12 16:51:35
    如果已经确认有动态库的情况下,那主要是因为动态库不在默认路径下,需要给系统指定库的路径或者把库放到默认路径下 第一种方法就是把库放到默认路径下 第二三种方法就是把库的路径加入默认路径 还有一种方法就是...
  • 静态库的代码在编译时就已连接到开发人员开发的应用程序中,而共享库只是在程序开始运行时才载入,在编译时, 只是简单地指定需要使用的库函数。动态库则是共享库的另一种变化形式。动态库也是在程序运行时载入,但...
  • linux编译动态库,ldd的时候not found

    万次阅读 2013-06-28 10:15:19
    1. 检查makefile脚本,-L指定动态库的位置,不然也不会编译通过。 2. 通过设置LD_LIBRARY_PATH, ldconfig也没有用。 最后才发现,编译出来的动态库名字本身叫libavatar.so.打包给应用程序的时候,被应用...
  • Linux下将几个.c文件(test1.c和test2.c)编译动态连接 libtest.so 的命令为: $ gcc test1.c test2.c -fPIC -shared -o libtest.so 选项说明: -shared: 该选项指定生成动态连接。 -fPIC : 表示编译为...
  • linux动态库生成命令 :g++ *.c -fPIC -shared -o lib**.so -lpthread -l....(-l后面为其他需要用到的动态库),命令不逐一解释, 需要注意的是,在动态库里调用动态库时,需要将用到的动态库指定下,也就是-l命令...
  • 1. PATH是可执行程序的查找路径 2. LD_LIBRARY_PATH是动态库的查找路径 3. 编译时可以临时指定头文件路径、动态库路径及动态库  g++ main.cpp -I ~/tools/include -L/usr/lib/x86-aaa -lboost_thread
  • 1 背景 在树莓派上开发执行程序,需要用到opencv,...(当然也可以用静态库编译) 所以需要拷贝出能用的so,与应用程序一起拷贝到新板子上,运行时加载我们的so。 2 cmake原本配置 find_package( OpenCV REQUIRED ...
  • 在Makefile中指定了自己的动态库和其路径 并且在该路径下有这个库文件 但是在执行时还会报错 2:原因与解决 这是因为我们指定的库,在这里是个软连接 本来应该指向真实的库文件,但是由于某些原因导致这里指向的...
  • 编译目标代码时指定动态库搜索路径;  2.环境变量配置文件下用LD_LIBRARY_PATH指定动态库搜索路径;  3.配置文件/etc/ld.so.conf中指定动态库搜索路径;  4.默认的动态库搜索路径/lib;  5.默认的动态...
  • 这个时候就用了了,指定动态库位置,在编译的时候,增加-Wl,--rpath=. 这个选项就可以修改,-Wl,--rpath=. 实现的是在当前文件夹下搜索动态库, linux执行时动态库指定当前文件夹,这样兼容性更好,拷贝到任何地方...
  • 这时就需要自己制作一个动态库,在编译的时候链接这个动态库,即可完成编译。 方法如下: ①创建一个xxx.c文件,将想要调用的子函数放进去(不可添加main函数) ②将xxx.c文件编译动态库:$(CC) -shared -fpic ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 629
精华内容 251
关键字:

linux编译指定动态库

linux 订阅