文章轉錄--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