最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解決Linux程序編譯鏈接動(dòng)態(tài)庫版本的相關(guān)問題

 更新時(shí)間:2017年01月25日 08:34:38   作者:littlewhite  
這篇文章主要介紹了解決Linux程序編譯鏈接動(dòng)態(tài)庫版本的相關(guān)問題,文中給出了詳細(xì)的介紹和示例代碼,相信對(duì)大家具有一定的參考借鑒價(jià)值,有需要的朋友們下面來一起看看吧。

前言

不同版本的動(dòng)態(tài)庫可能會(huì)不兼容,如果程序在編譯時(shí)指定動(dòng)態(tài)庫是某個(gè)低版本,運(yùn)行是用的一個(gè)高版本,可能會(huì)導(dǎo)致無法運(yùn)行。Linux上對(duì)動(dòng)態(tài)庫的命名采用libxxx.so.a.b.c的格式,其中a代表大版本號(hào),b代表小版本號(hào),c代表更小的版本號(hào),我們以Linux自帶的cp程序?yàn)槔?,通過ldd查看其依賴的動(dòng)態(tài)庫

 $ 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)

左邊是依賴的動(dòng)態(tài)庫名字,右邊是鏈接指向的文件,再查看libacl.so相關(guān)的動(dòng)態(tài)庫

 $ 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

我們發(fā)現(xiàn)libacl.so.1實(shí)際上是一個(gè)軟鏈接,它指向的文件是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

不管怎樣命名,只要按照規(guī)定的方式來生成和使用動(dòng)態(tài)庫,就不會(huì)有問題。而且我們往往是在機(jī)器A上編譯程序,在機(jī)器B上運(yùn)行程序,編譯和運(yùn)行的環(huán)境其實(shí)是有略微不同的。下面就說說動(dòng)態(tài)庫在生成和使用過程中的一些問題

動(dòng)態(tài)庫的編譯

我們以一個(gè)簡(jiǎn)單的程序作為例子

// filename:hello.c
#include <stdio.h>

void hello(const char* name)
{
 printf("hello %s!\n", name);
}

// filename:hello.h
void hello(const char* name);

采用如下命令進(jìn)行編譯

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

需要注意的參數(shù)是-Wl,soname(中間沒有空格),-Wl選項(xiàng)告訴編譯器將后面的參數(shù)傳遞給鏈接器,
-soname則指定了動(dòng)態(tài)庫的soname(簡(jiǎn)單共享名,Short for shared object name)

現(xiàn)在我們生成了libhello.so.0.0.1,當(dāng)我們運(yùn)行ldconfig -n .命令時(shí),當(dāng)前目錄會(huì)多一個(gè)軟連接

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

這個(gè)軟鏈接是如何生成的呢,并不是截取libhello.so.0.0.1名字的前面部分,而是根據(jù)libhello.so.0.0.1編譯時(shí)指定的-soname生成的。也就是說我們?cè)诰幾g動(dòng)態(tài)庫時(shí)通過-soname指定的名字,已經(jīng)記載到了動(dòng)態(tài)庫的二進(jìn)制數(shù)據(jù)里面。不管程序是否按libxxx.so.a.b.c格式命名,但Linux上幾乎所有動(dòng)態(tài)庫在編譯時(shí)都指定了-soname,我們可以通過readelf工具查看soname,比如文章開頭列舉的兩個(gè)動(dòng)態(tài)庫

 $ 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才會(huì)有一個(gè)這樣的軟連接

再看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,即便該動(dòng)態(tài)庫沒有按版本號(hào)的方式命名,但仍舊有一個(gè)軟鏈指向該動(dòng)態(tài)庫,而該軟鏈的名字就是soname指定的名字

所以關(guān)鍵就是這個(gè)soname,它相當(dāng)于一個(gè)中間者,當(dāng)我們的動(dòng)態(tài)庫只是升級(jí)一個(gè)小版本時(shí),我們可以讓它的soname相同,而可執(zhí)行程序只認(rèn)soname指定的動(dòng)態(tài)庫,這樣依賴這個(gè)動(dòng)態(tài)庫的可執(zhí)行程序不需重新編譯就能使用新版動(dòng)態(tài)庫的特性

可執(zhí)行程序的編譯

還是以hello動(dòng)態(tài)庫為例,我們寫一個(gè)簡(jiǎn)單的程序

// filename:main.c
#include "hello.h"

int main()
{
 hello("handy");
 return 0;
}

現(xiàn)在目錄下是如下結(jié)構(gòu)

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

libhello.so.0.0.1是我們編譯生成的動(dòng)態(tài)庫,libhello.so.0是通過ldconfig生成的鏈接,采用如下命令編譯main.c

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

報(bào)錯(cuò)找不到hello動(dòng)態(tài)庫,在Linux下,編譯時(shí)指定-lhello,鏈接器會(huì)去尋找libhello.so這樣的文件,當(dāng)前目錄下沒有這個(gè)文件,所以報(bào)錯(cuò)。建立這樣一個(gè)軟鏈,目錄結(jié)構(gòu)如下

├── 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鏈接指向?qū)嶋H的動(dòng)態(tài)庫文件libhello.so.0.0.1,再編譯main程序

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

這樣可執(zhí)行文件就生成了。通過以上測(cè)試我們發(fā)現(xiàn),在編譯可執(zhí)行程序時(shí),鏈接器會(huì)去找它依賴的libxxx.so這樣的文件,因此必須保證libxxx.so的存在

用ldd查看其依賴的動(dòng)態(tài)庫

 $ 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)

我們發(fā)現(xiàn)main程序依賴的動(dòng)態(tài)庫名字是libhello.so.0,既不是libhello.so也不是libhello.so.0.0.1。其實(shí)在生成main程序的過程有如下幾步

  1. 鏈接器通過編譯命令-L. -lhello在當(dāng)前目錄查找libhello.so文件
  2. 讀取libhello.so鏈接指向的實(shí)際文件,這里是libhello.so.0.0.1
  3. 讀取libhello.so.0.0.1中的SONAME,這里是libhello.so.0
  4. 將libhello.so.0記錄到main程序的二進(jìn)制數(shù)據(jù)里

也就是說libhello.so.0是已經(jīng)存儲(chǔ)到main程序的二進(jìn)制數(shù)據(jù)里的,不管這個(gè)程序在哪里,通過ldd查看它依賴的動(dòng)態(tài)庫都是libhello.so.0

而為什么這里ldd查看main顯示libhello.so.0為not found呢,因?yàn)閘dd是從環(huán)境變量$LD_LIBRARY_PATH指定的路徑里來查找文件的,我們指定環(huán)境變量再運(yùn)行如下

 $ 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)

可執(zhí)行程序的運(yùn)行

現(xiàn)在測(cè)試目錄結(jié)果如下

├── 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

這里我們把編譯環(huán)境和運(yùn)行環(huán)境混在一起了,不過沒關(guān)系,只要我們知道其中原理,就可以將其理清楚

前面我們已經(jīng)通過ldd查看了main程序依賴的動(dòng)態(tài)庫,并且指定了LD_LIBRARY_PATH變量,現(xiàn)在就可以直接運(yùn)行了

 $ ./main                        
hello Handy!

看起來很順利。那么如果我們要部署運(yùn)行環(huán)境,該怎么部署呢。顯然,源代碼是不需要的,我們只需要?jiǎng)討B(tài)庫和可執(zhí)行程序。這里新建一個(gè)運(yùn)行目錄,并拷貝相關(guān)文件,目錄結(jié)構(gòu)如下

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

這時(shí)運(yùn)行會(huì)main會(huì)發(fā)現(xiàn)

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

報(bào)錯(cuò)說libhello.so.0文件找不到,也就是說程序運(yùn)行時(shí)需要尋找的動(dòng)態(tài)庫文件名其實(shí)是動(dòng)態(tài)庫編譯時(shí)指定的SONAME,這也和我們用ldd查看的一致。通過ldconfig -n .建立鏈接,如下

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

再運(yùn)行程序,結(jié)果就會(huì)符合預(yù)期了

從上面的測(cè)試看出,程序在運(yùn)行時(shí)并不需要知道libxxx.so,而是需要程序本身記載的該動(dòng)態(tài)庫的SONAME,所以main程序的運(yùn)行環(huán)境只需要以上三個(gè)文件即可

動(dòng)態(tài)庫版本更新

假設(shè)動(dòng)態(tài)庫需要做一個(gè)小小的改動(dòng),如下

// filename:hello.c
#include <stdio.h>

void hello(const char* name)
{
 printf("hello %s, welcom to our world!\n", name);
}

由于改動(dòng)較小,我們編譯動(dòng)態(tài)庫時(shí)仍然指定相同的soname

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

將新的動(dòng)態(tài)庫拷貝到運(yùn)行目錄,此時(shí)運(yùn)行目錄結(jié)構(gòu)如下

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

此時(shí)目錄下有兩個(gè)版本的動(dòng)態(tài)庫,但libhello.so.0指向的是老本版,運(yùn)行ldconfig -n .后我們發(fā)現(xiàn),鏈接指向了新版本,如下

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

再運(yùn)行程序

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

沒有重新編譯就使用上了新的動(dòng)態(tài)庫, wonderful!

同樣,假如我們的動(dòng)態(tài)庫有大的改動(dòng),編譯動(dòng)態(tài)庫時(shí)指定了新的soname,如下

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

將動(dòng)態(tài)庫文件拷貝到運(yùn)行目錄,并執(zhí)行ldconfig -n . ,目錄結(jié)構(gòu)如下

├── 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

這時(shí)候發(fā)現(xiàn),生成了新的鏈接libhello.so.1,而main程序還是使用的libhello.so.0,所以無法使用新版動(dòng)態(tài)庫的功能,需要重新編譯才行

總結(jié)

在實(shí)際生產(chǎn)環(huán)境中,程序的編譯和運(yùn)行往往是分開的,但只要搞清楚這一系列過程中的原理,就不怕被動(dòng)態(tài)庫的版本搞暈。簡(jiǎn)單來說,按如下方式來做

  1. 編譯動(dòng)態(tài)庫時(shí)指定-Wl, -soname ,libxxx.so.a,設(shè)置soname為libxxx.so.a,生成實(shí)際的動(dòng)態(tài)庫文件libxxx.so.a.b.c,
  2. 編譯可執(zhí)行程序時(shí)保證libxx.so存在,如果是軟鏈,必須指向?qū)嶋H的動(dòng)態(tài)庫文件libxxx.so.a.b.c
  3. 運(yùn)行可執(zhí)行文件時(shí)保證libxxx.so.a.b.c文件存在,通過ldconfig生成libxxx.so.a鏈接指向libxxx.so.a.b.c
  4. 設(shè)置環(huán)境變量LD_LIBRARY_PATH,運(yùn)行可執(zhí)行程序

好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。

相關(guān)文章

  • Easypanel免費(fèi)的VPS主機(jī)面板 可跨平臺(tái)Linux和Windows

    Easypanel免費(fèi)的VPS主機(jī)面板 可跨平臺(tái)Linux和Windows

    Easypanel是一款免費(fèi)的功能強(qiáng)大集開通虛擬主機(jī),ftp空間,數(shù)據(jù)庫等功能為一體的主機(jī)控制面板,具備跨平臺(tái)(windows,linux),安全穩(wěn)定、操作簡(jiǎn)便等特點(diǎn),感興趣的小伙伴們可以關(guān)注一下
    2017-07-07
  • 在Linux系統(tǒng)上創(chuàng)建軟連接和硬連接的方法

    在Linux系統(tǒng)上創(chuàng)建軟連接和硬連接的方法

    這篇文章主要介紹了在Linux系統(tǒng)上創(chuàng)建軟連接和硬連接的方法,通過執(zhí)行 man ln 命令,可以看到這是在文件之間建立鏈接,而沒有提及是軟鏈接或硬鏈接,文中通過代碼和圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2024-08-08
  • 詳解Linux文件操作知識(shí)點(diǎn)

    詳解Linux文件操作知識(shí)點(diǎn)

    在本篇文章中我們給大家詳細(xì)分享了關(guān)于Linux文件操作的相關(guān)知識(shí)點(diǎn)內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。
    2018-09-09
  • Ubuntu下Telnet服務(wù)器的配置方法

    Ubuntu下Telnet服務(wù)器的配置方法

    這篇文章主要介紹了Ubuntu下Telnet服務(wù)器的配置方法的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-11-11
  • linux 基礎(chǔ)命令大全

    linux 基礎(chǔ)命令大全

    學(xué)過Linux的人都會(huì)知道,Linux中的命令的確是非常多,但是玩過Linux的人也從來不會(huì)因?yàn)長(zhǎng)inux的命令如此之多而煩惱,本文介紹了linux 基礎(chǔ)命令,有興趣的可以了解一下。
    2016-10-10
  • Ubuntu 18.04上安裝 phpMyAdmin的詳細(xì)教程

    Ubuntu 18.04上安裝 phpMyAdmin的詳細(xì)教程

    這篇文章主要介紹了Ubuntu 18.04上安裝 phpMyAdmin的詳細(xì)教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-12-12
  • Ubuntu使用國(guó)內(nèi)源出現(xiàn)Hash Sum mismatch錯(cuò)誤的解決

    Ubuntu使用國(guó)內(nèi)源出現(xiàn)Hash Sum mismatch錯(cuò)誤的解決

    這篇文章主要介紹了Ubuntu使用國(guó)內(nèi)源出現(xiàn)Hash Sum mismatch錯(cuò)誤的解決,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-04-04
  • linux下使用U盤拷文件方式

    linux下使用U盤拷文件方式

    這篇文章主要介紹了linux下使用U盤拷文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • 如何解決win10與Ubuntu16.04時(shí)間不同步的問題的方法

    如何解決win10與Ubuntu16.04時(shí)間不同步的問題的方法

    本篇文章主要介紹了如何解決win10與Ubuntu16.04時(shí)間不同步的問題的方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2017-05-05
  • CentOS7環(huán)境中DHCP配置教程

    CentOS7環(huán)境中DHCP配置教程

    大家好,本篇文章主要講的是CentOS7環(huán)境中DHCP配置教程,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-11-11

最新評(píng)論

双牌县| 鸡泽县| 刚察县| 新晃| 奎屯市| 布尔津县| 哈巴河县| 衡东县| 临海市| 土默特右旗| 乌什县| 独山县| 白城市| 富源县| 高州市| 中西区| 阜南县| 宁陕县| 内黄县| 张北县| 吉安县| 重庆市| 交城县| 郓城县| 定安县| 六枝特区| 永和县| 松滋市| 南宫市| 西乌珠穆沁旗| 双桥区| 西吉县| 盐城市| 仪陇县| 长武县| 游戏| 内丘县| 锡林郭勒盟| 姜堰市| 凌源市| 新闻|