-L -Wl,-rpath-link -Wl,-rpath區別精講

目錄

 

前言

關於gcc這三個參數,參考了諸多文檔後,仍然理解上有偏差,仿照下面博客中的方法,自己調試了一波,總算是理解了。還是建議大家動手實踐一下。

參考資料如下:

源碼準備

新建三個文件:test.c hello.c world.c ,其源碼依賴關係爲:test.c 依賴 hello.c;hello.c 依賴 world.c

源碼內容

test.c

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

hello.c

#include<stdio.h>
void hello(void);
void main(void)
{
    hello();
}

world.c

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

嘗試編譯,保證源碼沒有問題

# -o 指定輸出文件
[root@localhost testc]# ls
hello.c  test.c  world.c
[root@localhost testc]# gcc -o hehe *.c
[root@localhost testc]# ls
hehe  hello.c  test.c  world.c
[root@localhost testc]# ./hehe 
hello world.

編譯

首先編譯world.c

# -shared 編譯鏈接庫
# -fPIC 我的理解是編譯鏈接庫時給代碼動態分配內存
[root@localhost testc]# gcc -shared -fPIC -o libworld.so world.c
[root@localhost testc]# ls
hello.c  libworld.so  test.c  world.c
[root@localhost testc]# ldd libworld.so 
	linux-vdso.so.1 =>  (0x00007ffd7498f000)
	libc.so.6 => /lib64/libc.so.6 (0x00007fcb49815000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fcb49dea000)

#上述命令和下面的等價,建議選取單條命令即可:gcc -shared -fPIC -o libworld.so world.c
# -c 只激活預處理,編譯,和彙編,也就是他只把程序做成obj文件
[root@localhost testc]# gcc -c -fPIC world.c 
[root@localhost testc]# ls
hello.c  test.c  world.c  world.o
[root@localhost testc]# gcc -shared -fPIC -o libworld.so world.o
[root@localhost testc]# ls
hello.c  libworld.so  test.c  world.c  world.o
[root@localhost testc]# ldd libworld.so 
	linux-vdso.so.1 =>  (0x00007ffd0dfa9000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f4357dcb000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f43583a0000)

編譯並鏈接hello.c

# -lxxx 指定需要動態鏈接的庫文件
# -L 指定動態連接庫文件的位置(編譯時)
# . 指當前路徑
# 下面編譯出的libhello.so文件已經顯式依賴libworld.so文件,但是沒有找到libworld.so的位置
[root@localhost testc]# gcc -shared -fPIC -o libhello.so hello.c -lworld -L.
[root@localhost testc]# ls
hello.c  libhello.so  libworld.so  test.c  world.c
[root@localhost testc]# ldd libhello.so 
	linux-vdso.so.1 =>  (0x00007ffe61b89000)
	libworld.so => not found
	libc.so.6 => /lib64/libc.so.6 (0x00007ff73cc1e000)
	/lib64/ld-linux-x86-64.so.2 (0x00007ff73d1f4000)

調試編譯test.c

[root@localhost testc]# ls
hello.c  libhello.so  libworld.so  test.c  world.c

# 編譯出錯,提示找不到hello
[root@localhost testc]# gcc -o haha test.c 
/tmp/ccQCWcSW.o: In function 'main':
test.c:(.text+0x5): undefined reference to 'hello'
collect2: error: ld returned 1 exit status

# 添加libhello.so的鏈接索引,並指定庫的搜索路徑爲'.'(當前路徑)
# 依然編譯失敗,提示找不到libworld.so,該庫被libhello.so依賴,並提示建議使用-rpath 或 -rpath-link解決
[root@localhost testc]# gcc -o haha test.c -lhello -L.
/usr/bin/ld: warning: libworld.so, needed by ./libhello.so, not found (try using -rpath or -rpath-link)
./libhello.so: undefined reference to 'world'
collect2: error: ld returned 1 exit status

# 手動添加libworld.so的依賴,編譯通過,查看haha的鏈接庫,已經顯式指出依賴,但是沒有找到其位置
[root@localhost testc]# gcc -o haha test.c -lhello -L. -lworld
[root@localhost testc]# ldd haha 
	linux-vdso.so.1 =>  (0x00007fff556ea000)
	libhello.so => not found
	libworld.so => not found
	libc.so.6 => /lib64/libc.so.6 (0x00007f1ff0c97000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f1ff106b000)

# 執行編譯出的haha,執行報錯,提示找不到依賴庫
[root@localhost testc]# ./haha 
./haha: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory

#修改系統環境變量'LD_LIBRARY_PATH',增加索引庫的位置,查看依賴OK,執行haha, 結果OK, 清空'LD_LIBRARY_PATH'
[root@localhost testc]# export LD_LIBRARY_PATH=/home/testc/  && echo $LD_LIBRARY_PATH
/home/testc/
[root@localhost testc]# ldd haha 
	linux-vdso.so.1 =>  (0x00007ffd647d2000)
	libhello.so => /home/testc/libhello.so (0x00007fb7aa063000)
	libworld.so => /home/testc/libworld.so (0x00007fb7a9e60000)
	libc.so.6 => /lib64/libc.so.6 (0x00007fb7a9a8e000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fb7aa266000)
[root@localhost testc]# ./haha 
hello world.
[root@localhost testc]# export LD_LIBRARY_PATH=  && echo $LD_LIBRARY_PATH

# 將-lworld 替換爲 -Wl,-rpath-link=. ,編譯OK,依然找不到索引庫,添加LD_LIBRARY_PATH後,執行OK 
[root@localhost testc]# gcc -o haha test.c -lhello -L. -Wl,-rpath-link=.
[root@localhost testc]# ldd haha 
	linux-vdso.so.1 =>  (0x00007ffdf67c0000)
	libhello.so => not found
	libc.so.6 => /lib64/libc.so.6 (0x00007fbdbb94b000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fbdbbd1f000)
[root@localhost testc]# ./haha 
./haha: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
[root@localhost testc]# export LD_LIBRARY_PATH=/home/testc  && echo $LD_LIBRARY_PATH
/home/testc
[root@localhost testc]# ldd haha 
	linux-vdso.so.1 =>  (0x00007fff89504000)
	libhello.so => /home/testc/libhello.so (0x00007fc9e75c6000)
	libc.so.6 => /lib64/libc.so.6 (0x00007fc9e71f3000)
	libworld.so => /home/testc/libworld.so (0x00007fc9e6ff1000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fc9e77c9000)
[root@localhost testc]# ./haha 
hello world.
[root@localhost testc]# export LD_LIBRARY_PATH=  && echo $LD_LIBRARY_PATH

# 將-Wl,-rpath-link=. 換成 -Wl,-rpath=. 編譯OK, 查看鏈接庫OK,執行OK 
# 修改LD_LIBRARY_PATH後,鏈接庫的位置沒有變化
[root@localhost testc]# gcc -o haha test.c -lhello -L. -Wl,-rpath=.
[root@localhost testc]# ls
haha  hello.c  libhello.so  libworld.so  test.c  world.c
[root@localhost testc]# ldd haha 
	linux-vdso.so.1 =>  (0x00007fff86195000)
	libhello.so => ./libhello.so (0x00007f4c11254000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f4c10e81000)
	libworld.so => ./libworld.so (0x00007f4c10c7f000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f4c11457000)
[root@localhost testc]# ./haha 
hello world.
[root@localhost testc]# export LD_LIBRARY_PATH=/home/testc/  && echo $LD_LIBRARY_PATH
/home/testc/
[root@localhost testc]# ldd haha 
	linux-vdso.so.1 =>  (0x00007ffc9f36c000)
	libhello.so => ./libhello.so (0x00007f35cf07c000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f35ceca9000)
	libworld.so => ./libworld.so (0x00007f35ceaa7000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f35cf27f000)
[root@localhost testc]# export LD_LIBRARY_PATH=  && echo $LD_LIBRARY_PATH


結論

  • 編譯時鏈接庫需要分爲兩類: 直接引用 間接引用
  • 直接引用 被源碼中直接調用的庫
  • 間接引用 被調用庫的依賴庫
  • -lxxx 指定具體的庫名稱,編譯時需要顯式指定直接引用的庫名稱
  • -L 指定鏈接庫的位置,編譯時需要顯式指定直接引用的庫位置
  • -Wl,-rpath-link ,用於編譯時指定間接引用的庫位置
    如果知道所有間接引用的庫文件名稱,並且不嫌麻煩,也可以用-lxxx顯式指定每一個庫(不推薦-lxxx)
  • -Wl,-rpath ,有兩個作用:
    1. 用於編譯時指定間接引用的庫位置,作用同-Wl,-rpath-link
    2. 用於運行時指定所有引用庫的位置,作用同修改環境變量(LD_LIBRARY_PATH),並且庫路徑引用優先級高於LD_LIBRARY_PATH
  • 使用建議
    1. 編譯命令中使用-Wl,-rpath-link 指定間接引用庫位置(編譯時),使用-Wl,-rpath 指定引用庫位置(運行時)
    2. -Wl,-rpath-link 在 -Wl,-rpath 前
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章