2010-11-05 30 views
25

考慮,我們有以下的情況:瞭解如何動態鏈接適用於UNIX

  • 名爲program計劃,動態地取決於libfoo.so
  • libfoo.so取決於什麼(當然,這取決於libstdc++和東西,但我想我們可以省略)

program完美運行。

突然,libfoo代碼發生變化,現在某些函數內部使用func_bar()函數,該函數由另一個庫libbar.so提供。

libfoo.so重新編譯,現在取決於libbar.soprogram保持不變,它仍然只取決於libfoo.so

現在當我執行program它抱怨他找不到func_bar()

這裏是我的問題:

  • libfoo.so接口並沒有改變,只是其實現。爲什麼program必須明確鏈接libbar.so
  • 是不是依賴樹遞歸?我會認爲,因爲libfoo.so取決於libbar.so,libbar.so本來會自動添加到program,的依賴列表中,而沒有重新編譯。但是,ldd program表明情況並非如此。

這似乎不可思議的是人們必須重新編譯(重新鏈接)每個二進制依賴於某些庫,每次該庫的依賴關係發生變化。我有什麼解決方案來防止這種情況發生?

+0

你能發佈一個最小化的配置來重現問題嗎? Vitaut在他的帖子後的評論似乎描述了同樣的過程,並沒有達到同樣的問題。也許如果你採取簡單的步驟,我們可以幫助回答這個問題? – 2010-11-05 20:29:35

回答

17

如果您還沒有鏈接libfoo.solibbar,則會出現問題。在編譯可執行文件時,默認情況下,鏈接程序不會讓您留下未定義的引用。但是,當您編譯共享庫時,它將 - 它會期望它們在鏈接時滿意。這樣libfoo可以使用由program本身導出的函數 - 當您嘗試運行它時,動態鏈接器預計func_bar()program提供。問題是出像這樣:

foo.c是自足)

export LD_RUN_PATH=`pwd` 
gcc -Wall -shared foo.c -o libfoo.so 
gcc -Wall -L. p.c -lfoo -o p 

在這一點上,./p正確運行,如你所願。然後,我們創建libbar.so和修改foo.c使用它:

gcc -Wall -shared bar.c -o libbar.so 
gcc -Wall -shared foo.c -o libfoo.so 

在這一點上,./p給你描述的錯誤。如果我們檢查ldd libfoo.so,我們注意到它確實有而不是libbar.so有依賴 - 這是錯誤。要糾正錯誤,我們必須正確鏈接libfoo.so

gcc -Wall -L. -lbar -shared foo.c -o libfoo.so 

在這一點上,./p再次運行正常,並ldd libfoo.so顯示了libbar.so的依賴。

+0

你說得對:我沒有用'libbar.so'鏈接。現在就像一個魅力!非常感謝 ! – ereOn 2010-11-08 08:22:58

2

您沒有提供任何系統信息,您是否使用glibc?如果是的話,這是什麼命令的輸出:

LD_DEBUG =文件程序

還要檢查"How to write shared (ELF) libraries"(PDF)(無論您使用的glibc與否)

1

你的程序不具有鏈接libbar.so。

我認爲這個問題是由於在構建後者時未能指定libbar.so作爲libfoo.so的依賴而造成的。 我不知道什麼是您使用的編譯系統,但CMake的它可以如下進行:

add_library(bar SHARED bar.c) 

add_library(foo SHARED foo.c) 
target_link_libraries(foo bar) 

add_executable(program program.c) 
target_link_libraries(program foo) 

正如你可以看到program僅與foolibfoo.so)和foo只有barlibbar.so)鏈接。或者可能找不到libbar.so。嘗試在LD_LIBRARY_PATH環境變量中指定其目錄的路徑。

+1

問題是CMake在幕後做了什麼,它可能足夠聰明,可以爲程序 – 2010-11-05 16:39:02

+0

建立正確的鏈接命令@Peer Stritzinger:很好的問題。我想到了這一點,並做了一些實驗(建立'program',而'foo'沒有鏈接到'bar',然後建立'foo'和'bar',但不是'program')並且工作。所以在這種情況下,cmake方面的魔法似乎不太可能,儘管確實很聰明=)。 – vitaut 2010-11-05 16:52:12

+1

這是否真的回答了這個問題?當然,將'libbar'與'libfoo'連接起來,然後*與'program'連接就可以獨立工作,而不依賴於構建系統。但是,如果'program'與'libfoo'鏈接,然後'libfoo'更新爲'libbar'鏈接,則可能不是這種情況。如果你的CMake腳本,如果'libfoo'改變爲與libbar鏈接沒有任何魔力,'program'顯然與'libfoo'重新鏈接。 – 2010-11-05 17:12:02

8

Fedora動態鏈接由ld-linux.so.2執行。 動態鏈接器使用/etc/ld.so.cache和/etc/ld.so.preload來查找庫文件。

運行ldconfig來告訴系統libfoo應該在哪裏查找libbar。

ldconfig查找/ lib,/ usr/lib和/etc/ld.so.conf中列出的任何目錄。 您可以檢查程序使用ldd的庫。

有關每條命令的手冊頁上均提供更多詳細信息。

以下是使用共享庫的應用程序示例。
Program.cc

#include "foo.h" 
#include <iostream> 

int main(int argc, char *argv[]) 
{ 
    for (int i = 0; i < argc; ++i) { 
     std::cout << func_foo(argv[i]) << std::endl; 
    } 
} 

foo.h中

#ifndef FOO_H 
#define FOO_H 
#include <string> 
std::string func_foo(std::string const &); 
#endif 

foo.cc

#include "foo.h" 

std::string func_foo(std::string const &arg) 
{ 
    return arg + "|" + __func__; 
} 

bar.h

#ifndef BAR_H 
#define BAR_H 
#include <string> 
std::string func_bar(); 
#endif 

bar.cc

#include "bar.h" 

std::string func_bar() 
{ 
    return __func__; 
} 

使用libfoo.so作爲共享庫進行構建。
克++ -Wall -Wextra -fPIC -shared foo.cc -o libfoo.so
克++ -lfoo -L./ -Wall -Wextra program.cc foo.h中-o程序
LDD程序
...
libfoo.so =>未找到

更新/etc/ld.so.cache中
須藤LDCONFIG /家庭/托比亞斯/項目/株/所以/

LDD表明動態鏈接器找到libfoo.so
ldd程序
...
libfoo.so => /home/tobias/projects/stubs/so/libfoo.so(0x00007f0bb9f15000)

添加調用libbar.so在libfoo.so
新foo.cc

#include "foo.h" 
#include "bar.h" 

std::string func_foo(std::string const &arg) 
{ 
    return arg + "|" + __func__ + "|" + func_bar(); 
} 

生成libbar.so和重建libfoo.so
克++ -Wall -Wextra -fPIC -shared bar.cc -o libbar.so
克++ -Wall -Wextra -fPIC -shared libbar.so FOO .cc -o libfoo.so
ldd libfoo.so
...
libbar.so =>沒有發現

LDD程序
...
libfoo.so => /home/tobias/projects/stubs/so/libfoo.so(0x00007f49236c7000)
libbar.so =>沒有發現
這表明,動態鏈接器還發現libfoo.so但不libbar的。所以
再次更新/etc/ld.so.cache並重新檢查。
須藤LDCONFIG /家庭/托比亞斯/項目/株/所以/
LDD libfoo.so
...
libbar.so => /home/tobias/projects/stubs/so/libbar.so(0x00007f935e0bd000)

LDD程序
...
libfoo.so => /home/tobias/projects/stubs/so/libfoo.so(0x00007f2be4f11000)
libbar.so => /首頁/托比亞斯/項目/存根/ so/libbar.so(0x00007f2be4d0e000)

B找到了libfoo.so和libbar.so。

注意這最後一步對應用程序沒有影響。 如果你真的嚴格的運行ldconfig是一種重新鏈接。 奇怪或不連接器需要知道它鏈接的庫的依賴關係。 還有很多其他的方法來實現這一點,但這是選擇。

+0

感謝您的信息:) – ereOn 2010-11-08 08:21:46

1

這不應該是這種情況,除非有關bar_func 符號的變化。使用「nm」命令獲取程序和共享對象中的符號轉儲 - 查看是否存在不匹配以及原因。

+1

我讀到的問題是,'bar_func()'的變化是以前它沒有被使用,但現在它被使用。 – 2010-11-08 06:43:17