ld鏈結動態庫靜態庫問題

2021-08-16 10:21:08 字數 3117 閱讀 5674

在使用redis寫c

**的時候遇到的問題,安裝

redis

時make install

可以看到:

mkdir -p/usr/local/include/hiredis /usr/local/lib

cp -a hiredis.h async.h read.h sds.h adapters/usr/local/include/hiredis

cp -a libhiredis.so/usr/local/lib/libhiredis.so.0.13

cd /usr/local/lib &&ln -sflibhiredis.so.0.13 libhiredis.so

cp -a libhiredis.a/usr/local/lib

把redis

的標頭檔案放進了

/usr/local/include/hiredis

,把動態庫

libhiredis.so

和靜態庫

libhiredis.a

都放進了

/usr/local/lib

於是我就在我的

makefile

裡面寫:

gcc main.c -i/usr/local/include-l/usr/local/lib -lhiredis -o main
ok,

gcc通過生成可執行檔案

main

,但是一執行

main

報錯:

error while loading shared libraries:

libhiredis.so.0.13: cannot open sharedobject file: no such file or directory

於是產生了兩個疑問:

1. usr/local/lib 

裡面libhiredis.so

和靜態庫

libhiredis.a

都有,為什麼用的是

.so而不是.a?

gcc編譯鏈結時寫法都是

-l庫所在路徑

-l庫名,是否有寫法可以區分指明要鏈結動態庫還是靜態庫?

2. 我在makefile

裡面不是已經指明

so的位置,並且相應位置確實有

libhiredis.so.0.13

,為什麼執行的時候還是找不到?

針對第乙個問題,查了資料之後發現: ld

在鏈結的時候如果路徑下相同庫名的靜態庫和動態庫都有,那麼會優先使用動態鏈結庫,動態鏈結庫不存在才會使用靜態鏈結庫;

如果指明要使用靜態鏈結庫,那麼需要在編譯命令中加入

-static

引數;

gcc main.c -i/usr/local/include-l/usr/local/lib -lhiredis -static -o main

後來又做了測試發現,

-static

是乙個全域性引數,並不是只對乙個鏈結生效,對所有的鏈結都生效。也就是一旦寫上之後所有庫都只會去找靜態庫,就不能指定某些庫鏈靜態庫,而其它庫鏈動態庫;

針對第二個問題其實是很顯然的,

"link time"

(鏈結時)和

"runtime"

(執行時),兩個基本概念要弄清楚,不能混在一起。

-l選項屬於鏈結時,編譯出來的可執行檔案不知道

-l選項後面的值,當然找不到對應的

so。而

-rpath,ld_library_path

都屬於執行時

查資料之後發現執行的時候查詢動態庫路徑順序如下:

1. 可執行檔案中自帶的編譯時寫入的rpath、runpath

2. ld_library_path 指定的地方

3. ldconfig 指定的地方:根據/etc/ld.so.cache查詢

4. /lib

5. /usr/lib

所以相對應的解決辦法有:

1.      使用rpath把so的路徑指明並記錄到二進位制檔案中

gcc main.c -i/usr/local/include -l/usr/local/lib -lhiredis –o main -wl,--rpath=/usr/local/lib

重新編譯再執行發現無報錯了 關於

rpath

、runpath

的詳細相關作用方法見

2.      把libredis.so所在路徑加入到ld_library_path環境變數中

export ld_library_path= /usr/local/lib:$ld_library_path

3.      使用ldconfig修改/etc/ld.so.cache

ldconfig

命令的用途主要是在預設搜尋目錄

/lib

和/usr/lib

以及動態庫配置檔案

/etc/ld

.so.conf

內所列的目錄下,搜尋出可共享的動態鏈結庫(格式如

lib*.so*),

進而建立出動態裝入程式

(ld.so)

所需的連線和快取檔案(一般預設為

/etc/ld.so.cache

),此檔案儲存已排好序的動態鏈結庫名字列表

ldconfig

通常在系統啟動時執行,而當使用者安裝了乙個新的動態鏈結庫時,就需要手工執行這個命令。

由於我們是新安裝了

redis

/etc/ld.so.conf

下面加一行

/usr/local/lib

/usr/local/mysql/lib

(需要root

許可權),儲存過後

ldconfig

一下(需要

root

許可權)

4.      把新安裝的so拷到/lib或/usr/lib下

ld 動態鏈結庫配置

一 ldconfig ldconfig是乙個動態鏈結庫管理命令,為了讓動態鏈結庫為系統所共享,還需執行動態鏈結庫的管理命令 ldconfig。ldconfig 命令的用途,主要是在預設搜尋目錄 lib和 usr lib 以及動態庫配置檔案 etc ld.so.conf內所列的目錄下,搜尋出可共享的動...

動態鏈結庫 靜態鏈結庫

包含標頭檔案和庫 idir 指定編譯查詢標頭檔案的目錄,常用於查詢第三方的庫的標頭檔案,例 gcc test.c i.inc o test。ldir 指定鏈結時查詢lib的目錄,常用於查詢第三方庫。llibrary 指定額外鏈結的lib庫 巨集定義 dmacro 以字串 1 預設值 定義 macro...

靜態鏈結庫 動態鏈結庫

庫是寫好的現有的,成熟的,可以復用的 現實中每個程式都要依賴很多基礎的底層庫,不可能每個人的 都從零開始,因此庫的存在意義非同尋常。本質上來說庫是一種可執行 的二進位制形式,可以被作業系統載入記憶體執行。庫有兩種 靜態庫 a lib 和動態庫 so dll windows上對應的是.lib dll ...