【Linux C】Linux環境下編譯靜態庫與動態庫
目錄
靜態庫在程式編譯時會被連線到目的碼中,程式執行時將不再需要該靜態庫。編譯之後程式檔案大,但載入快,隔離性也好。
動態庫在程式編譯時並不會被連線到目的碼中,而是在程式執行是才被載入,因此在程式執行時還需要動態庫存在。多個應用程式可以使用同一個動態庫,啟動多個應用程式的時候,只需要將動態庫載入到記憶體一次即可。
編譯動態庫:
-shared 該選項指定生成動態連線庫(讓聯結器生成T型別的匯出符號表,有時候也生成弱連線W型別的匯出符號),不用該標誌外部程式無法連線。相當於一個可執行檔案 -fPIC:表示編譯為位置獨立的程式碼,不用此選項的話編譯後的程式碼是位置相關的所以動態載入時是通過程式碼拷貝的方式來滿足不同程序的需要,而不能達到真正程式碼段共享的目的。 -L.:表示要連線的庫在當前目錄中 -ltest:編譯器查詢動態連線庫時有隱含的命名規則,即在給出的名字前面加上lib,後面加上.so來確定庫的名稱
配置庫位置: LD_LIBRARY_PATH:這個環境變數指示動態聯結器可以裝載動態庫的路徑。 當然如果有root許可權的話,可以修改/etc/ld.so.conf檔案,然後呼叫 /sbin/ldconfig來達到同樣的目的,不過如果沒有root許可權,那麼只能採用輸出LD_LIBRARY_PATH的方法了。
ldd命令可以檢視可執行檔案依賴的庫檔案。
1. 測試庫的程式檔案
1.1 測試庫的標頭檔案test.h
//test.h #ifndef __LIBTEST_H #define __LIBTEST_H void myprintf(); int myadd(int a,int b); #endif
1.2 測試庫的原始檔test.c
//test.c
#include <stdio.h>
#include "test.h"
void myprintf(){
printf("this is library test func!\r\n");
}
int myadd(int a,int b){
return (a+b);
}
1.3 測試應用程式原始檔 main.c
//main.c
#include <stdio.h>
#include "test.h"
int main()
{
myprintf();
int a,b,c;
a=5;
b=10;
c = myadd(a,b);
printf("c=%d\n",c);
return 0;
}
2. 靜態庫的編譯流程
2.1 生成 test.o 的連結檔案
gcc -c test.c
2.2 生成 libtest.a 的靜態庫檔案
ar -r libtest.a test.o
2.3 生成 main 的可執行檔案
gcc main.c -ltest -L. -o main
2.4 測試 main 執行結果
./main
3. 動態庫的編譯流程
3.1 生成 test.o 的連結檔案
gcc -fPIC -c test.c
3.2 生成 libtest.so 的動態庫檔案
gcc -shared -o libtest.so test.o
3.3 配置動態庫路徑的環境變數
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(pwd)
echo $LD_LIBRARY_PATH
3.4 生成 main 的可執行檔案
gcc main.c -ltest -L. -o main
3.5 測試 main 執行結果
./main
附錄:
在linux下可以用export命令來設定這個值,比如
在linux終端下輸入:export LD_LIBRARY_PATH=/usr/local/lib: $LD_LIBRARY_PATH:
然後再輸入:export
即會顯示是否設定正確
export方式在重啟後會失效,所以也可以用 vim /etc/bashrc ,修改其中的LD_LIBRARY_PATH變數。
例如:LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib。
或者:
可以在 ~/.bashrc 或者 ~/.bash_profile 中加入 export 語句,前者在每次登陸和每次開啟 shell 都讀取一次,後者只在登陸時讀取一次。我的習慣是加到 ~/.bashrc 中,在該檔案的未尾,可採用如下語句來使設定生效:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
修改完後,記得關掉當前終端並重新開啟一個新的終端,從而使上面的配置生效。