文章轉錄--Linux環境撰寫Shared Library
撰寫範例程式
| 1 | bool isPalindrome(char* word); | 
{: file=”pal.h” }
| 1 | 
 | 
{: file=”pal.cpp” }
編譯shared library
在終端機輸入以下GCC指令,注意這裡我們有-c選項,這告訴GCC不要進行linking stage,如果沒加GCC就會報錯,因為一個應用程式一定會有main()函式,但是Library不需要main()函式。這行指令將會產生一個pal.o檔
| 1 | g++ -fPIC -c -Wall pal.cpp | 
接下來我們要用pal.o檔和以下指令產生真正的library。ld是linker program,通常會被g++呼叫。-shared告訴ld製作一個shared object,以pal.o為輸入輸出名為libpal.so。在Linux通常shared libraries的副檔名都是.so。
| 1 | ld -shared pal.o -o libpal.so | 
使用shared library
首先建立一個main.cpp來呼叫我們的library的isPalindrome函式。在程式中我們include函式庫的標頭檔pal.h
| 1 | 
 | 
{: file=”main.cpp” }
接下來我們可能直接用g++ -Wall main.cpp -lpal這行指令連接我們的shared library,c但是如果這麼做我們會得到下面錯誤訊息。這是因為ld在預設的搜尋路徑下找不到libpal.so
| 1 | /usr/bin/ld: cannot find -lpal: No such file or directory | 
其中一種解法是用g++告入ld函式庫的位置
| 1 | g++ -Wall -L<libpal.so的路徑> -Wl,-rpath=<libpal.so的路徑> main.cpp -lpal | 
例如
| 1 | g++ -Wall -L/home/faye -Wl,-rpath=/home/faye/ main.cpp -lpal | 
其中:
- -Wall是用來檢查所有編譯警告的
- L式shared library的路徑,讓- ld知道要去那裡尋找
- -Wl是一連串用逗號分隔的linker指令,在這裡有- -rpath表示library 的路徑會被嵌入到主程式的執行檔,因此loader在執行主程式的時候可以找到library
 
-L與-rpath的區別是:
- -L是給linker用的
- -rpath是被嵌入到執行檔給- loader看的
最後g++會幫我們產生a.out執行檔,執行方式和結果如下
| 1 | $ ./a.out | 
安裝自己開發的Shared Libraries
用剛剛的方式連接Shared Libraries的方法有個缺點,也就是你的編譯指令直接給其他人的話可能會出錯,因為Shared Libraries在每個人的電腦上的位置可能都不一樣。因此rpath和-L選項的路徑也會不一樣。而我們的解決方法之一就是LD_LIBRARY_PATH
LD_LIBRARY_PATH
如果我們直接在終端機輸入指令echo $LD_LIBRARY_PATH看LD_LIBRARY_PATH的值,他應該會是空的,除非你以前曾經設定過他。要是用LD_LIBRARY_PATH我們只需要以下指令
| 1 | export LD_LIBRARY_PATH=<Shared Library所在資料夾>:$LD_LIBRARY_PATH | 
例如
| 1 | export LD_LIBRARY_PATH=/home/faye:$LD_LIBRARY_PATH | 
這時在輸入一次echo $LD_LIBRARY_PATH應該就會輸出/home/faye:。而這時候我們編譯main.cpp的時候就算沒有-rpath選項編譯出來的執行檔也不會找不到libpal.so
| 1 | g++ -Wall -L/home/faye/sotest main.cpp -lpal | 
你可以先嘗試看看在還沒設定
LD_LIBRARY_PATH之前或是利用unset LD_LIBRARY_PATH指令清空LD_LIBRARY_PATH變數,所編譯出來的執行檔會出現什麼問題。
你應該會發現編譯的過程沒有任何錯誤訊息,但是一旦你執行編譯出來的執行檔a.out就會跳出錯誤訊息./a.out: error while loading shared libraries: libpal.so: cannot open shared object file: No such file or directory,這表示執行檔loader找不到libpal.so檔
{: .prompt-tip }
不過LD_LIBRARY_PATH其實只適合在開發階段拿來測試library用,因為它不需要root權限,但是函式庫發布給大家使用的時候,要求每個人都去設定LD_LIBRARY_PATH並不是個好方法。
ldconfig : 安裝Shared Libraries正統方法
首先我們先清除上一個教學的LD_LIBRARY_PATH設定,可以用unset LD_LIBRARY_PATH指令來清除。
接下來我們必須把我們的函式庫複製到/usr/lib資料夾。複製函式庫到/usr/lib必須擁有root權限,因此我們用sudo來幫助我們。
| 1 | sudo mv <函式庫所在資料夾>/libpal.so /usr/lib | 
例如
| 1 | sudo mv /home/faye/libpal.so /usr/lib | 
接下來更新系統中儲存可用libraries的cache。
| 1 | sudo ldconfig | 
你可以用下面指令來確定cache已經被更新了而且系統可以找到你的函式庫
| 1 | ldconfig -p | grep libpal | 
系統應該會回應你
| 1 | libpal.so (libc6,x86-64) => /lib/libpal.so | 
接下來你就可以用下面指令編譯我們的執行檔了,而且這次我們不需要-rpath,也不需要-L選項!!因為現在我們的函式庫已經位於系統預設的函式庫搜尋路徑下了。
| 1 | g++ -Wall main.cpp -lpal | 
參考:
https://www.fayewilliams.com/2015/07/07/creating-a-shared-library/
https://www.fayewilliams.com/2015/07/14/installing-and-accessing-shared-libraries/  
文章轉錄--Linux環境撰寫Shared Library