精华内容
下载资源
问答
  • 很多c程序在windows下是以dll形式展现的,在linux则是以so 形式展现的。windows一般不会因为编译dll文件的编译器版本不同而出先dll文件不能执行。...如何查看动态链接库文件(so后缀的)是否能在当前l...

    很多c程序在windows下是以dll形式展现的,在linux则是以so 形式展现的。

    windows一般不会因为编译dll文件的编译器版本不同而出先dll文件不能执行。

    linux下,不同版本内核的linux下编译的c程序,在其他版本的linux下就容易出现无法执行的问题。

    主要原因:支持程序的内核相对于编译时的内核较高或者版本相对于编译时的内核较低。

    如何查看动态链接库文件(so后缀的)是否能在当前linux系统下可用?

    首先,要看他依赖的相关文件是否存在,查看命令:

    ldd file.so

    假如,想查看jnative的动态链接库在某个版本的linux下是否被支持,先切换到文件所在目录,命令:

    ldd libJNativeCpp.so

    若正常,显示如下:

    libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x0069c000)

    libm.so.6 => /lib/tls/libm.so.6 (0x00111000)

    libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00562000)

    libc.so.6 => /lib/tls/libc.so.6 (0x00134000)

    /lib/ld-linux.so.2 (0x0097b000)

    若不正常可能显示如下:

    ./libJNativeCpp.so: /lib/tls/libc.so.6: version `GLIBC_2.4' not found (required by ./JNativeCpp.so)

    libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x0047e000)

    libm.so.6 => /lib/tls/libm.so.6 (0x00111000)

    libc.so.6 => /lib/tls/libc.so.6 (0x0056e000)

    libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00c3d000)

    /lib/ld-linux.so.2 (0x0097b000)

    这里是那个有名的jni第三方类库的默认的lib,上边的错误信息显示就是说我们的libJNativeCpp.so是在2.4内核下编译的,当前内核版本不支持。

    经过查看,我当前的linux版本的内核是2.6高于libJnativeCpp.so编译时的内核。

    展开全文
  • 不同版本的动态可能会不兼容,如果程序在编译时指定动态是某个低版本,运行是用的一个高版本,可能会导致无法运行。Linux上对动态的命名采用libxxx.so.a.b.c的格式,其中a代表大版本号,b代表小版本号,c代表...
  • 不同版本的动态可能会不兼容,如果程序在编译时指定动态是某个低版本,运行是用的一个高版本,可能会导致无法运行。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,运行可执行程序
    展开全文
  • 有时候在编译程序时 。会有 error while loading shared libraries: xxx.so.0...这是由于动态不在链接程序ld的搜索目录中。 解决方法有两个: 将动态复制到ld的搜索路径下。通常是在/usr/local/lib,或者/us
    有时候在编译程序时 。会有 
    error while loading shared libraries: xxx.so.0:cannot open shared object file: No such file or directory
    
    

    这是由于动态库不在链接程序ld的搜索目录中。

    解决方法有两个:

    1. 将动态库复制到ld的搜索路径下。通常是在/usr/local/lib,或者/usr/lib下
    2. 修改ld的搜索路径。也就是将动态库所在位置添加到/etc/ld.so.conf文件末尾。再执行/sbin/ldconfig –v更新ld查找路径。
    注意:修改/etc/ld.so.conf文件和执行/sbin/ldconfig 命令均需要root权限

    展开全文
  • 不同版本号的动态可能会不兼容,假设程序在编译时指定动态是...Linux上对动态的命名採用libxxx.so.a.b.c的格式。当中a代表大版本号号。b代表小版本号号,c代表更小的版本号号。我们以Linux自带的cp程序为例...

    不同版本号的动态库可能会不兼容,假设程序在编译时指定动态库是某个低版本号。执行是用的一个高版本号,可能会导致无法执行。

    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,执行可执行程序

    EOF

    转载于:https://www.cnblogs.com/zhchoutai/p/8726906.html

    展开全文
  • 我们很多c程序在windows下是以dll形式展现的,在linux则是以so 形式展现的。 windows一般不会因为编译dll文件的... 但是linux下,不同版本内核的linux编译的c程序,在其他版本的linux下就容易出现无法执行的...
  • Qt在linux系统下编译动态链接库的问题。 原始Qt工程是在Windows系统中用Qt 5.11编写。包括两部分:主程序(.exe)工程+动态链接库(.dll)工程。 在VM中创建了Ubuntu系统,并安装了Qt5.9.0版本(Qt 5.9.0 Linux 安装包的...
  • 前言不同版本的动态可能会不兼容,如果程序在编译时指定动态是某个低版本,运行是用的一个高版本,可能会导致无法运行。Linux上对动态的命名采用libxxx.so.a.b.c的格式,其中a代表大版本号,b代表小版本号,c...
  • linux下查看动态链接库so文件的依赖的相关组件  我们很多c程序在windows下是以dll形式展现的,在linux则是以so 形式展现的。  windows一般不会因为编译dll文件的编译器版本不同而出先dll文件不能执行。  ...
  • 解决Linux动态链接库无法加载问题

    千次阅读 2016-03-10 10:14:52
    Linux环境下,根据第三方提供的动态链接库和API利用C语言进行开发,编译链接通过后,当运行时报错说无法加载动态链接库例如: 疑问就来了,动态链接库我使用的全路径(例如:/home/cyren/src/lib/libaivse000.so....
  • 解决Linux程序编译链接动态版本的相关问题发布时间:2017-03-06 09:08来源:互联网当前栏目:web技术类前言不同版本的动态可能会不兼容,如果程序在编译时指定动态是某个低版本,运行是用的一个高版本,可能会...
  • 我们很多c程序在windows下是以dll形式展现的,在linux则是以so 形式展现的。  windows一般不会因为编译...  那我们如何看别人给我们提供的动态链接库文件(so后缀的)是否能在当前linux系统下可用
  • 在运行PointNet的可视化程序时,作者只提供了linux平台下的动态链接库程序源码,自己的windows平台下无法调用。发现是动态链接库的文件格式不对,遂学习如何将.so文件转换成.dll文件(PS:前提是你有文件的.cpp源码)...
  • 关于Linux链接三方的问题。我在CentOS7.6 系统上安装了ZeroMQ三方,安装路径是:/usr/local/zeromq 这个安装路径是本人自定义的。 我在当前用户的主目录下配置了如下的环境变量值:vim ~/.bash_profile ...
  •  但是linux下,不同版本内核的linux编译的c程序,在其他版本的linux下就容易出现无法执行的问题。主要可能是支持程序的内核相对于编译时的内核较高或者版本相对于编译时的内核较低。 那我们如何看别
  • 创建 .so 文件跟一般的ELF文件的生成相似,不同之处在于:1、添加 -fPIC -shared作为gcc的选项;其中:PIC表示 Position Independent Code,用于指示gcc将.c文件编译为目标代码.o;-shared用户指示gcc连接器输出T...
  • 表示把当前目录加入到动态链接库查找的目录中去重新运行 成功! 上述方法设置是临时的 另外一种方法: sudo vim /etc/ld.so.conf 添加路径 如 ./ (表示当前目录)或者 so文件所在路径 添加保存后运行 sudo ...
  • 可直接将树莓派的wiringPi拿下来:(正常是直接在上位机上...1. 正常我们先要交叉编译wiringPi编译出的适合树莓派,这时候交叉编译可执行程序的试试,链接库的格式也是正确的。 2. 通过-I -L来指定 arm-linux
  • 编译的适用于linux环境qt程序无法使用sogou输入法等基于fcitx的输入法的动态链接库,libfcitxplatforminputcontextplugin.so (x86_64),Qt5.11.0编译 经测试,可以用于Archlinux、Manjaro(x86_64)Mathematica...
  • 通过c++调用matlab中自己编写的函数(是通过将该函数在matlab中mcc编译成.so,然后c++中调用这个.so的方式),成功编译后(编译时也出现一些错误,详情点这里),但是成功编译完后,居然不能运行。为什么编译通过不...

空空如也

空空如也

1 2 3 4
收藏数 64
精华内容 25
关键字:

linuxso库无法链接编译

linux 订阅