1. 程式人生 > >linux下靜態庫和動態庫使用的從無到有

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了。