既然顯示加載這麼多優點,那麼爲什麼實際生產中很少碼農使用它呢, 主要原因還是起使用不是很方便,需要開發人員多寫不少代碼。所以不被大多數碼農使用,還有一個重要原因應該是能提前發現錯誤,在部署的時候就能發現缺少哪些so,而不是等到實際上限運行的時候才發現缺東少西。
下面舉個工作中最常碰到的問題,來引申出本篇內容吧。
寫一個最簡單的so, tmp.cpp
1. int test()
2. {
3. return 20;
4. }
編譯=>鏈接=》運行, 下面main.cpp 內容請參見上一篇文章。
[stevenrao]$ g++ -fPIC -c tmp.cpp [stevenrao]$ g++ -shared -o libtmp.so tmp.o [stevenrao]$ mv libtmp.so /tmp/ [stevenrao]$ g++ -o demo -L/tmp -ltmp main.cpp [stevenrao]$ ./demo ./demo: error while loading shared libraries: libtmp.so: cannot open shared object file: No such file or directory [stevenrao]$ ldd demo linux-vdso.so.1 => (0x00007fff7fdc1000) libtmp.so => not found |
這個錯誤是最常見的錯誤了。運行程序的時候找不到依賴的so。一般人使用方法是修改LD_LIBRARY_PATH這個環境變量
export LD_LIBRARY_PATH=/tmp
[stevenrao]$ ./demo
test
這樣就OK了, 不過這樣export 只對當前shell有效,當另開一個shell時候,又要重新設置。可以把export LD_LIBRARY_PATH=/tmp 語句寫到 ~/.bashrc中,這樣就對當前用戶有效了,寫到/etc/bashrc中就對所有用戶有效了。
前面鏈接時候使用 -L/tmp/ -ltmp 是一種設置相對路徑方法,還有一種絕對路徑鏈接方法。
[stevenrao]$ g++ -o demo /tmp/libtmp.somain.cpp
[stevenrao]$ ./demo
test
[stevenrao]$ ldd demo
linux-vdso.so.1=> (0x00007fff083ff000)
/tmp/libtmp.so(0x00007f53ed30f000)
絕對路徑雖然申請設置環境變量步驟,但是缺陷也是致命的,這個so必須放在絕對路徑下,不能放到其他地方,這樣給部署帶來很大麻煩。所以應該禁止使用絕對路徑鏈接so。
搜索路徑分兩種,一種是鏈接時候的搜索路徑,一種是運行時期的搜索路徑。像前面提到的 -L/tmp/ 是屬於鏈接時期的搜索路徑,即給ld程序提供的編譯鏈接時候尋找動態庫路徑;而LD_LIBRARY_PATH則既屬於鏈接期搜索路徑,又屬於運行時期的搜索路徑。
這裏需要介紹鏈-rpath鏈接選項,它是指定運行時候都使用的搜索路徑。聰明的同學馬上就想到,運行時搜索路徑,那它記錄在哪兒呢。也像. LD_LIBRARY_PATH那樣,每部署一臺機器就需要配一下嗎。呵呵,不需要..,因爲它已經被硬編碼到可執行文件內部了。看看下面演示
1. [stevenrao] $ g++ -o demo -L /tmp/ -ltmp main.cpp
2. [stevenrao] $ ./demo
3. ./demo: error while loading sharedlibraries: libtmp.so: cannot open shared object file: No such file or directory
4. [stevenrao] $ g++ -o demo -Wl,-rpath /tmp/ -L/tmp/ -ltmp main.cpp
5. [stevenrao] $ ./demo
6. test
7. [stevenrao] $ readelf -d demo
8.
9. Dynamic section at offset 0xc58 contains 26entries:
10. Tag Type Name/Value
11. 0x0000000000000001(NEEDED) Shared library: [libtmp.so]
12. 0x0000000000000001(NEEDED) Shared library:[libstdc++.so.6]
13. 0x0000000000000001(NEEDED) Shared library: [libm.so.6]
14. 0x0000000000000001(NEEDED) Shared library:[libgcc_s.so.1]
15. 0x0000000000000001(NEEDED) Shared library: [libc.so.6]
16. 0x000000000000000f(RPATH) Library rpath: [/tmp/]
17. 0x000000000000001d(RUNPATH) Library runpath: [/tmp/]
看看是吧,編譯到elf文件內部了,路徑和程序深深的耦合到一起
so搜索路徑,還有一個類似於-path,叫LD_RUN_PATH環境變量, 它也是把路徑編譯進可執行文件內,不同的是它只設置RPATH。