linux 動態庫版本庫管理及靜態庫
一、庫命名
我們在linux下使用一些庫時,會發現其後面帶有一些數字,例如:libc.so.1 。形如lib*.so.x.y.z是有一套命名規則(*表示你給so的名字),x表示major version ,y表示minor version z表示release version ,引入這套規則的目的是保證程式的更新,相容等,
linux共有的so有三種名字: (1)real name:其命名規則為lib*.so.x.y.z,在它的開頭,包含有soname資訊。程式執行時真正呼叫的so,也就是裡面是真正含有程式碼的,
(2)soname(short for shared object name):其命名規則為lib*.so.x,
(3)link name:其命名規則為lib*.so就是我們在連結時,所使用的名字,比如 -lc ,這樣,編譯器就會去尋找libc.so.x.y.z ,如果有多個,編譯器去尋找最新的。當然,使用者也可以直接指定全名,比如,/**/**/**/lib*.so.1.1.2,這個linkname其實是一個虛擬的,如果存在realname
soname,那這個linkname其實是不存在的。既然這樣,linkname作用是什麼,linkname使得使用者不用去記住那些數字編號了,直接利用前面的名字就可以找到所使用的so。
*************上面這段紅色是字是前端時間寫的,開始以為名字為linkname的檔案其實可以不用存在,後面發現似乎有錯誤,編譯器其實是根據linkname去找到realname,然後提取出soname的。
二、關於動態庫
下面我們自己編譯一些so來試試看:我使用cmake來管理工程,當然也可以直接使用gcc,為了方便理解。操作中兩者我都會採用
######動態庫的生成及使用
(1) cmake版
project(test_version) cmake_minimum_required(VERSION 2.6) set(CMAKE_C_FLAGS "-fPIC") set(CMAKE_BUILD_TYPE Release ON) add_library(test_version SHARED so.c) SET_TARGET_PROPERTIES(test_version PROPERTIES VERSION 1.2.3 SOVERSION 1)
#realname版本號為1.2.3
我們可以看到生成的動態庫情況如下:
大家可以通過readelf -d **.so.**檢視相關情況
下面來呼叫生成的動態庫,這裡我們呼叫的就是libtest_version.so
<span style="font-size: 14px;">project(test)
cmake_minimum_required(VERSION 2.6)
include_directories(/home/JunYao/workspace/test_so_version/test/)
ADD_EXECUTABLE(test test.c)
TARGET_LINK_LIBRARIES(test </span><span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size:12px;">/home/guagua/workspace/useless/test_so_version/so_version/build/libtest_version.so</span></span><span style="font-size: 14px; font-family: Arial, Helvetica, sans-serif;">)</span>
最後生成test可執行檔案,我們 ldd test 看一下,編譯器將soname讀入test,:
找不到動態庫,為啥,因為,連結器和裝載器並不共享動態庫的路勁,解決這種問題有三類方法
(i) 將相應的動態庫拷貝到/lib 或 /usr/lib 目錄下
(ii)新增LD_LIBRARY 並指定相應動態庫路徑
(iii)更新 /etc/ld.so.conf.d/ ***.conf 在裡面新增相應的動態庫路徑
(1) gcc版
gcc -shared -Wl,-soname,libtest_version.so.0 -o libtest_version.so.0.0.0 so.o
-soname,libtest_version.so.0表示指定器soname的名字,不過這個so不會自動生成,可以利用ldconfig來生成,並且linkname也需要手動生成
**************************************************************************這塊有點迷惑*********************************************************
利用gcc來編譯測試程式:
gcc test.c -L /home/guagua/workspace/useless/test_so_version/so_version/build/ -ltest_version -o test 連結的還是剛剛利用cmake生成的動態庫,連結沒有問題,但是有意思的事情發生了:
找不到動態庫,為啥,因為,gcc連結器和裝載器並不共享動態庫的路勁,解決這種問題有三類方法
(i) 將相應的動態庫拷貝到/lib 或 /usr/lib 目錄下
(ii)新增LD_LIBRARY 並指定相應動態庫路徑
(iii)更新 /etc/ld.so.conf.d/ ***.conf 在裡面新增相應的動態庫路徑
那為何剛剛用cmake可以呢,在用cmake的時候,上面的三個方法我都沒有使用。我們來看下生成的兩個test有啥不同:由上面可知,最起碼,大小就不同,會不會是cmake編譯出來的,已經包含了裝載資訊? 我把test和動態庫放到另外一臺電腦,開始不能執行,但是,當我建立/home/guagua/workspace/useless/test_so_version/so_version/build/ 並把相應動態庫拷貝進去,就能執行,這個能說明cmake生成的可執行檔案,動態庫的載入路徑也有寫入?
二、關於靜態庫
利用cmake生成靜態庫時,就沒啥版本號的概念了,就是隻生成一個libtest_version.a
靜態連結不成功,是因為現在都是使用glibc ,一些靜態庫預設不安裝,所以靜態編譯連結libtest_version.a 是沒問題,但是連結libc.a就出問題了