撰寫範例程式
1
bool isPalindrome(char* word);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "pal.h"
#include <string.h>
bool isPalindrome(char* word)
{
bool ret = true;
char *p = word;
int len = strlen(word);
char *q = &word[len-1];
for (int i = 0 ; i < len ; ++i, ++p, --q)
{
if (*p != *q)
{
ret = false;
}
}
return ret;
}
編譯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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "pal.h"
#include <iostream>
using namespace std;
int main()
{
while (1)
{
char buffer[64] = {0};
cin >> buffer;
if (isPalindrome(buffer))
{
cout << "Word is a palindrome" << endl;
}
else
{
cout << "Word is not a palindrome" << endl;
}
}
return 0;
}
接下來我們可能直接用g++ -Wall main.cpp -lpal
這行指令連接我們的shared library,c但是如果這麼做我們會得到下面錯誤訊息。這是因為ld
在預設的搜尋路徑下找不到libpal.so
1
2
/usr/bin/ld: cannot find -lpal: No such file or directory
collect2: error: ld returned 1 exit status
其中一種解法是用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
2
3
4
5
$ ./a.out
ada
Word is a palindrome
team
Word is not a palindrome
安裝自己開發的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
檔
不過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/