Linux 下的动态链接库问题
生活随笔
收集整理的這篇文章主要介紹了
Linux 下的动态链接库问题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在 Linux 開發時,我們經常會看到一些形如 xxx.so 的名稱出現,其中 so 是 Shared Object 的縮寫,即可以共享的目標文件,也就是我們所稱為的動態鏈接庫,和在 Windows 下大家玩游戲時遇到的 xxx.dll 錯誤中的文件是一個類型的。
面試中經常會問到以下問題:
- 怎么創建一個動態庫?
- 動態庫文件的后綴名是什么?
- 怎么使用一個動態庫?
- 動態庫的命名規范?
- 系統默認的動態庫的查找路徑?
- 動態庫顯示連接所使用的系統庫是什么?
一、什么是庫
庫是寫好的現有的,成熟的,可以復用的代碼。現實中每個程序都要依賴很多基礎的底層庫,不可能每個人的代碼都從零開始,因此庫的存在意義非同尋常。本質上來說庫是一種可執行代碼的二進制形式,可以被操作系統載入內存執行。
庫有兩種:
靜態庫(.a、.lib)
動態庫(.so、.dll)
在一個程序的編譯過程中,分為以下幾個步驟:預處理,編譯,匯編,鏈接。本文中討論的鏈接庫就是針對最后一個步驟「鏈接」而言的。
動態庫和靜態庫的區別
左圖為靜態鏈接庫,右圖為動態鏈接庫
對于靜態鏈接庫而言在鏈接階段,會將匯編生成的「目標文件.o」與引用到的庫一起鏈接打包到可執行文件中。因此對應的鏈接方式稱為靜態鏈接:
- 靜態鏈接庫對函數庫的鏈接是放在編譯時期完成的。程序在運行時與函數庫就沒有了任何的聯系。
- 它比較浪費空間和資源,因為所有相關的目標文件與牽涉到的函數庫被鏈接合成一個可執行文件。
- 靜態庫對程序的更新和發布也會帶來麻煩。如果靜態庫更新了,所有使用它的應用程序都需要重新編譯、部署、發布給用戶。
靜態鏈接可以理解為最后生成了一個「單文件免安裝綠色版」的程序,優點在于移植的時候只需要移動這一個文件,缺點在于文件體積非常大,為了解決這樣的問題,就有了動態鏈接庫。動態鏈接庫在程序編譯時并不會被連接到目標代碼中,而是在程序運行時才被載入。
- 不同的應用程序如果調用相同的庫,那么在內存里只需要有一份該共享庫的實例,可以實現進程之間的資源共享。(因此動態庫也稱為共享庫)規避了空間浪費問題。
- 動態庫在程序運行時才被載入,也解決了靜態庫對程序的更新、部署和發布帶來的麻煩。用戶只需要更新動態庫即可將一些程序升級變得簡單,增量更新。
動態庫連接到系統空間,如果多個程序連接了同一個庫,那么只需要一份,優點在于編譯程序的時候不會將對應的庫文件全部打包在生成的程序中,而是保留了到對應庫的鏈接,缺點就是移植的時候如果只移動了對應的程序沒有安裝相關的庫的話,就會看到類似以下喜聞樂見的結果了。
在 Linux 下一個動態庫有y三個不同名字的文件組成:
- soname 文件
lib + 鏈接庫名字 + .so + .版本號 - real name 文件
lib + 鏈接庫名字 + .so + .版本號.次版本號.發行號 - linker name 文件
lib + 鏈接庫名字 + .so
二、創建一個動態庫
有了上面關于庫的一些基礎知識之后,我們可以開始嘗試創建一個動態庫來供程序使用了。
比如我們有一個求最大值的函數 max(int a,int b,int c) ,放在文件 max.c 中文件內容如下:
int max(int a, int b, int c) {int max = ( a < b ) ? b : a;return ( ( max < c ) ? c : max ); }可以通過:
gcc -fPIC -shared -o libmax.so max.c- 將其編譯為共享庫,-fPIC 是編譯選項,PIC 是 Position Independent Code 的縮寫,表示要生成位置無關的代碼,這是動態庫需要的特性;
- -shared 是鏈接選項,告訴gcc生成動態庫而不是可執行文件。
- 為了讓用戶知道我們的動態庫中有哪些接口可用,我們需要編寫對應的頭文件,比如可以寫一個 max.h :
設置一個驅動函數來測試我們編寫的動態庫:
#include <stdio.h> #include "max.h"int main(int argc, char *argv[]) {int a = 12, b = -2, c = 120;printf("The max value of 12, -2 and 120 is %d.\n", max(a, b, c));return 0; }通過 gcc test.c -L. -lmax 來生成 a.out,其中-lmax表示要鏈接 libmax.so,-L. 表示搜索要鏈接的庫文件時包含當前路徑。
同一目錄下同時存在同名的動態庫和靜態庫,比如 libmax.so 和 libmax.a 都在當前路徑下,則gcc會優先鏈接動態庫。
但是這樣直接運行的話,會出現一個錯誤:
./a.out: error while loading shared libraries: libmax.so: cannot open shared object file: No such file or directory由于 Linux 是通過/etc/ld.so.cache文件搜尋要鏈接的動態庫的,而/etc/ld.so.cache是 ldconfig 程序讀取/etc/ld.so.conf文件生成的,本次使用的動態庫libmax.so并不在對應的目錄下,就會導致程序無法找到對應的動態鏈接庫,這樣我們的解決方法有二:
-
如果僅僅是本地使用,可以在編譯后指定一個環境變量:LD_LIBRARY_PATH=. ./a.out ,這樣程序會在本地尋找
如果需要在系統層面共享這個庫,可以把 libmax.so 所在的路徑添加到 /etc/ld.so.conf 中,再以 -
root 權限運行 ldconfig 程序,更新 /etc/ld.so.cache
具體采用的方法因使用場景而異,如果僅僅是測試用途的話,可以直接使用添加環境變量的方式解決。
小結
動態鏈接庫是各個系統中的一個重要的組成部分且在 Linux 開發相關領域中尤為重要,也是一個面試的高頻考點,除了動態鏈接庫以外,還有以下相關知識也是高頻考點,在面試前一定要準備好:
Linux 下 make 與 makefile。用什么參數指定 makefile 文件?什么是默認的makefile 文件?
Linux 靜態庫的使用,怎么創建一個靜態庫?怎么使用一個靜態庫?靜態庫文件的后綴名是什么?靜態庫的命名規范?
link
總結
以上是生活随笔為你收集整理的Linux 下的动态链接库问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux 中的动态链接库和静态链接库是
- 下一篇: Ubuntu 16.04 安装 caff