1. 程式人生 > >linux 動態庫版本庫管理及靜態庫

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,

應用程式在連結時,所找到的庫,它的資訊是寫在real name,在連結時,從realname中讀取出soname,寫入應用程式中,應程式再通過soname找到real name

                                                        (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就出問題了