-L、-rpath和-rpath-link的區別


以下結論及分析僅針對動態庫。

結論:

(1)-rpath和-rpath-link都可以在鏈接時指定庫的路徑;

(2)運行可執行文件時,-rpath-link指定的路徑不再有效(鏈接器沒有將庫的路徑包含進可執行文件中),

            而-rpath指定的路徑還有效(因為鏈接器已經將庫的路徑包含在可執行文件中);

(3)-L指定的是鏈接時的庫路徑,生成的可執行文件在運行時庫的路徑仍由LD_LIBRARY_PATH環境變量指定;

(4)不管采用何種選項鏈接,當提示找不到動態庫時均可通過設置LD_LIBRARY_PATH解決。

 

【轉http://blog.csdn.net/q1302182594/article/details/42102961】

關於這3個參數的說明,有不少資料,但是看完了還是覺得模糊,分不清它們的區別。本文將用實驗的方法去探討這3個參數的區別。

1、三個.c文件

1.1 world.c

 

[cpp]  view plain  copy
 
  1. #include<stdio.h>  
  2. void world(void) {  
  3.     printf("world.\n");  
  4. }  

1.2 hello.c

[plain]  view plain  copy
 
  1. #include <stdio.h>  
  2. void world(void);  
  3. void hello(void) {  
  4.     printf("hello\n");  
  5.     world();  
  6. }  

1.3 test.c

 

 

[plain]  view plain  copy
 
  1. void main(void) {  
  2.     hello();  
  3. }  

2、生成動態庫

 

    參照《Linux靜態庫與動態庫制作》,將hello.c和world.c分別生成動態庫

 

[plain]  view plain  copy
 
  1. ubuntu $ gcc -c hello.c world.c  
  2. ubuntu $ gcc -shared -o libhello.so hello.o  
  3. ubuntu $ gcc -shared -o libworld.so world.o  

 

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

 

    由上圖可見,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:

 

[plain]  view plain  copy
 
  1. ubuntu $ gcc -shared -o libworld.so world.o -lhello -L .  

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

 


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

3、編譯test.c

3.1 -L

    由於test.c直接依賴於libhello.so,因此使用-lhello -L

 

[plain]  view plain  copy
 
  1. ubuntu $ gcc test.c -lhello -L .  

    結果如下圖:



 

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

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

 

[plain]  view plain  copy
 
  1. ubuntu $ gcc test.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

 

[plain]  view plain  copy
 
  1. ubuntu 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參數:

 

[plain]  view plain  copy
 
  1. ubuntu $ export LD_LIBRARY_PATH=  
  2. ubuntu $ gcc test.c -lhello -L . -Wl,-rpath .  

    執行a.out,並且使用ldd命令查看a.out的依賴:

 

 

    由上圖可見,雖然沒有明確指出鏈接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移動進這個目錄。

 

[plain]  view plain  copy
 
  1. ubuntu $ mdir lib_tmp  
  2. ubuntu $ mv libhello.so lib_tmp/  
  3. ubuntu $ 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所在的路徑

 

[plain]  view plain  copy
 
  1. ubuntu $ export LD_LIBRARY_PATH=./lib_tmp  

    再次執行a.out,並且使用ldd查看此時a.out的依賴庫路徑:

 

 

    由上圖可見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所在的路徑:

 

[plain]  view plain  copy
 
  1. ubuntu $ export LD_LIBRARY_PATH=./lib_tmp/  

    再次執行a.out,並且使用ldd查看其依賴庫:


 

    由上圖可見,一切又恢復了正常。此時,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_tmp目錄中,而libhello.so則留在documents目錄中,使用以下命令對test.c進行編譯:

 

[plain]  view plain  copy
 
  1. ubuntu $ gcc test.c -lhello  -L . -Wl,-rpath-link ./lib_tmp  

   執行a.out並且使用ldd查看a.out的依賴庫:

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

    由上圖可見,libhello.so已經通過LD_LIBRARY_PATH找到,但是libworld.so由於沒有在LD_LIBRARY_PATH指定的路徑中,而且編譯時a.out又沒有包含庫的路徑,因此找不到。

    

 


免責聲明!

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



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