linux下靜態庫和動態庫使用的從無到有
首先我們先列出gcc編譯器的常用命令:
我們在來看看gcc的編譯流程,因為我們在開發工具中玩了太久,一般都會忽略這些細節的:
好,下面我們在來談一談靜態庫和動態庫
關於靜態庫和動態庫的優點和結構實現我們就不BB了。
ar是gnu歸檔工具,rcs表示(replace and create),我們就是要使用這個工具來給我們封裝靜態庫的。
#include "myprintf.h"
int main(void)
{
myprintf("hello gcc\r\n");
}
#ifndef myprintf_h #define myprintf_h #include <stdio.h> void myprintf(char* str); #endif
#include "myprintf.h"
void myprintf(char * str)
{
printf("%s\r\n",str);
}
#首先我們要把該檔案製作成.o檔案 ,然後使用ar工具將其更改為靜態庫
gcc -o myprintf.o -c myprintf.c
ar rcs libmyprintf.a myprintf.o
#進行靜態庫的連線工作
gcc -L . main.c -o main.o -lmyprintf
下面我們來說說動態庫的生成與呼叫
我們還是以上面的幾個.c檔案為例
首先我們來使用共享的,與地址無關的命令來編譯動態庫
gcc -I ./include -shared -fPIC -o ~/lib/libmyprintf.so ./src/myprintf.c//稍後說明為啥把生成的動態庫放到~/bin中
注意我們沒有加-c哦
然後我們進行動態庫的連線
gcc -I ./include -L ~/lib ./test/main.c -o main.o -lmyprintf
好了,這樣動態庫的連線工作就做完了。
然後我們進行LD_LIBRARY_PATH環境變數的配置
找到使用者目錄下的.bashrc在最後新增如下指令碼程式碼
# set lib so it includes user's private lib if it exists
if [ -d "$HOME/lib" ] ; then
export LD_LIBRARY_PATH="$HOME/lib"
fi
重新啟動bash,以重新載入配置檔案,此時在執行main.o則不會報錯,要不然會報找不到libmyprintf.so動態庫。
那麼這是為什麼呢,這是因為我們的作業系統預設的動態庫查詢路徑是去
/usr/lib
/lib
/lib64
這幾個目錄下查詢,為了不發生和系統動態庫的重疊問題我們在使用者目錄下建立lib資料夾,以存放我們自己的動態庫。
還有就是當我們將我們要呼叫的xxx.so動態庫放到了以上所說的目錄中去,我們在執行ldd也是沒有找到這個動態庫的,這是為什麼呢?
這就要牽涉到一個配置檔案了,linux作業系統會預設到該配置檔案中指定的路徑下面查詢動態庫,因為我們更改了檔案結構,但是linux有他自己的優化機制,所以我們得自己手動呼叫一個命令來時我們的檔案結構生效。
sudo /sbin/ldconfig
下面我們來提一提這個配置檔案是什麼?
假設想往上面兩個目錄以外加東西的時候,我們不配置環境變數的話,一定要修改/etc/ld.so.conf,然後再呼叫ldconfig,不然也會找不到 比如安裝了一個到/usr/local/mysql,mysql有一大堆library在/usr/local/mysql/lib下面,這時就需要在/etc/ld.so.conf下面加一行/usr/local/mysql/lib,儲存過後ldconfig一下,新的library才能在程式執行時被找到。
好了下面我們來整理一下動態庫放置位置的幾種方式
1:往/lib和/usr/lib裡面加東西,是不用修改/etc/ld.so.conf的,但是完了之後要調一下ldconfig
2:想往上面兩個目錄以外加東西的時候,一定要修改/etc/ld.so.conf,然後再呼叫ldconfig
3:如果想在這兩個目錄以外放lib,但是又不想在/etc/ld.so.conf中加東西(或者是沒有許可權加東西)。那也可以,就是export一個全域性變數LD_LIBRARY_PATH,然後執行程式的時候就會去這個目錄中找library。
說完這邊我們就又需要思考一個問題了,那就是我們用下載的原始碼,通過makefile進行編譯和連線,如果我們在./configure(忘了怎麼拼寫了,知道我的意思就行)指定我們的安裝路徑,此時生成的動態庫就放在我們指定的路徑下時,如我們置頂目錄下的./lib/,但是他並沒有修改我們的任何檔案和環境變數,他又是怎麼找到的呢?
那就不得不提到run path 這個名詞,就是執行時環境,也就是我們在連線的時候使用指定的命令,這個命令會在可執行檔案中寫入我們給定的動態庫查詢路徑,這樣我們在執行的時候就不需要再做什麼多餘的操作了~~!
那麼怎麼實現這樣的操作呢?
gcc -o mian.out main.c -I ../include -L ../lib -lmethod -Wl,-rpath=../lib
這裡又有兩種概念,一種叫做編譯與連結時查詢路徑,一種叫做執行時查詢路徑:
編譯與連結時查詢路徑:就是我們指定的-I 標頭檔案的路徑 -L動態庫的路徑 -lmethod動態庫的名稱,這裡的檔案只在編譯連結時進行參與
執行時查詢路徑: -rpath 就是執行時動態庫的查詢路徑,那麼你會問-Wl是什麼意思呢 ,可以自行man page一下,
我簡單的說 -Wl 就是一個gcc的選項,表示要呼叫聯結器ld,-rpath 是ld的的一個選項,表示指定程式執行時庫的路徑。
連結器的選項還有很多我們就不一一介紹了。只要我們明白原理就ok了。