ld 鏈接選項-L,-rpath-link,-rpath


轉載自: http://blog.csdn.net/q1302182594/article/details/42102961

1. 三個C文件

1. world.c

#include<stdio.h>  
void world(void)
{  
    printf("world.\n");  
} 

2. hello.c

#include <stdio.h> 
 
void world(void);  
void hello(void) 
{  
    printf("hello\n");  
    world();  
}  

3. main.c

void main(void) 
{  
    hello();  
}  

2. 編譯動態庫

gcc -c -fPIC hello.c world.c  
gcc -shared -o libhello.so hello.o  
gcc -shared -o libworld.so world.o  

-fPIC編譯選項是因為我是AMD64位系統,X86的系統似乎不需要

這時,生成的文件及其依賴如下圖:

 由上圖可見,libhello.so和libworld都依賴於linux-gate.so.1、libc.so.6以及/lib/ld-linux.so.2,並且這3個庫的路徑都以及硬編碼進libhello.so和libworld.so中了(=>右邊的部分)。然而,雖然libhello.so中調用了libworld.so的函數,但是在上圖中並沒有顯示出此關系。為了達到使libhello.so依賴於libworld.so的目的,在生成libhello.so時要鏈接到libworld.so:

gcc -shared -o libhello.so hello.o -lworld -L .  

 此時,再使用ldd查看libhello.so的依賴:

 由上圖可見,此時libhello.so已經依賴於libworld.so。

3. 編譯main.c

3.1: -L

gcc test.c -lhello -L .  

由上圖可見已經在-L指定的路徑找打了libhello.so,只是libhello.so還需要libworld.so。雖然它都在同一目錄下,但是還是沒有辦法自動找到libworld.so。

能不能使用-lworld將libworld.so也一並鏈接到test.c中呢?下面做一個嘗試:

gcc main.c -lhello -lworld -L .

 沒有報錯,成功生成a.out。執行a.out並且使用ldd查看a.out的依賴:

  由上圖可見,雖然使用-lworld參數將libworld.so鏈接到了a.out中,但是上面只顯示a.out依賴於libhello.so。由於找不到libhello.so(=> not found)的路徑,因此需要設置環境變量LD_LIBRARY_PATH

export LD_LIBRARY_PATH=/home/liyihai/documents 

再次執行a.out並使用ldd命令查看a.out的依賴庫:

 由上圖可見,libhello.so已經通過LD_LIBRARY_PATH環境變量找到,並且libworld.so也出現在a.out的依賴中! 結論:-L指定的是鏈接時的庫路徑,生成的可執行文件在運行時庫的路徑由LD_LIBRARY_PATH環境變量指定。

3.2: -rpath

根據3.1第1張圖的提示,由於libhello.so依賴於libworld.so,可以只用-rpath或者-rpath-link來指定。這里先使用-rpath。先清空LD_LIBRARY_PATH環境變量,然后重新編譯test.c並且帶上-rpath參數:

export LD_LIBRARY_PATH=  
gcc test.c -lhello -L . -Wl,-rpath .  

 

由上圖可見,雖然沒有明確指出鏈接libworld.so,但是libworld.so還是出現在a.out的依賴中。另外,雖然LD_LIBRARY_PATH已經清空,但是a.out還是可以執行,這說明庫的路徑已經被編譯進a.out中了。需要注意的是,libhello.so和libworld.so的路徑都是通過-rpath指定的路徑找到的。

3.2.1 實驗1

這時候,如果libhello.so和libworld.so的路徑改變了,將會發生什么情況呢?下面做一個實驗。創建一個lib_tmp目錄,然后將libhello.so和libworld.so移動進這個目錄。

mdir lib_tmp  
mv libhello.so lib_tmp/  
mv libworld.so lib_tmp/  

這時再執行a.out時,提示找不動態庫,使用ldd命令查看a.out的庫路徑:

由上圖紅色圈部分可見,libhello.so的路徑是not found的,並且libworld.so沒有出現在其中。這和3.1的情況是相同的。究其原因,就是要先找到libhello.so再去找libworl.so,因為是libhello.so依賴於libworld.so,而不是a.out依賴於libworld.so。由此可見,使用了-rpath參數指定庫的路徑后,生成的可執行文件的依賴庫路徑並非就固定不變了。而是執行時先從-rpath指定的路徑去找依賴庫,如果找不到,還是會報not fund。那么,這時候,LD_LIBRARY_PATH對a.out是否還有影響呢?下面將LD_LIBRARY_PATH設為當前libhello.so和libworld.so所在的路徑

export LD_LIBRARY_PATH=./lib 

 

由上圖可見LD_LIBRARY_PATH還是起作用的!由上圖可見,和使用-rpath指定路徑的效果是一樣的。

3.2.2 實驗2

 將LD_LIBRARY_PATH清空,然后將libhello.so移動到lib_tmp中,而libworld.so則留在documents目錄中。執行a.out,並且使用ldd查看此時a.out的依賴庫:

由上圖可見,找不到libhello.so。這時,再指定LD_LIBRARY_PATH的路徑為libhello.so所在的路徑:

export LD_LIBRARY_PATH=./lib

由上圖可見,一切又恢復了正常。此時,libhello.so是通過LD_LIBRARY_PATH找到的,而libworld.so則是通過-rpath指定的路徑找到的。

3.2.3 回顧

其實,經過測試,在3.1小節中,如果先指定LD_LIBRARY_PATH的值為libhello.so和libworld.so所在的路徑,然后再編譯test.c(執行3.1節的第1條編譯命令),是可以成功編譯的,並不會報3.1小節第1張圖的那種錯誤。也就是說,LD_LIBRARY_PATH不僅指定可執行文件的庫路徑,還指定了庫所依賴於其它庫的路徑。

3.2.4 結論   

並非指定-rpath參數后,就拋棄LD_LIBRARY_PATH環境變量,只是多了個可選的依賴庫路徑而已。

3.3 -rpath-link

 先將LD_LIBRARY_PATH的值清空,然后將libworld.so移動到lib目錄中,而libhello.so則留在linker目錄中,使用以下命令對main.c進行編譯:

 gcc test.c -lhello  -L . -Wl,-rpath-link ./lib

找不到 libhello.so,這在預料之中。下面指定LD_LIBRARY_PATH的值為libhello.so的路徑,然后在執行a.out,並且查看a.out的依賴:

  由上圖可見,libhello.so已經通過LD_LIBRARY_PATH找到,但是libworld.so由於沒有在LD_LIBRARY_PATH指定的路徑中,而且編譯時a.out又沒有包含庫的路徑,因此找不到。這對比3.2.2可以得出結論:-rpath和-rpath-link都可以在鏈接時指定庫的路徑;但是運行可執行文件時,-rpath-link指定的路徑就不再有效(鏈接器沒有將庫的路徑包含進可執行文件中),而-rpath指定的路徑還有效(因為鏈接器已經將庫的路徑包含在可執行文件中了。) 最后,不管使用了-rpath還是-rpath-link,LD_LIBRARY_PATH還是有效的。

可以參考另一博文http://www.cnblogs.com/flyinggod/p/8026567.html  查看ld的搜索路徑


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM