Linux下靜態庫和動態庫
函數庫分為靜態庫和動態庫
動態庫(格式為libname.so[.主版本號.次版本號.發行號])。在程序編譯時並不會被鏈接到目標代碼中,而是在程序運行時才被載入。
靜態庫是目標文件.a的歸檔文件(格式為libname.a)。如果在編譯某個程序時鏈接靜態庫,則鏈接器將會搜索靜態庫並直接拷貝到該程序的可執行二進制文件到當前文件中;
看定義不太好理解,下面舉例說明上述概念:
動態庫
動態庫(格式為libname.so[.主版本號.次版本號.發行號])。在程序編譯時並不會被鏈接到目標代碼中,而是在程序運行時才被載入。
$ gcc -fPIC -Wall -c add.c $ gcc -shared -o libadd.so add.o $ gcc -o main main.c –ladd
在運行main前,需要註冊動態庫的路徑。將庫文件拷貝到/lib或者/usr/lib下(系統默認搜索庫路徑)。
$ cp libadd.so /lib //通常采用的方法, cp lib*.so /lib
$ ./main
實例測試:
add.c
int add(int a, int b){
return a + b;
}
main.c
#include <stdio.h> int add(int a, int b); int main() { int res = add(3, 4); printf("res = %d\n", res); return 0; }
這裏我們要將add.c生成動態庫使得main.c能編譯運行。
gcc -fPIC -Wall -c add.c
gcc -shared add.o -o libadd.so
sudo cp libadd.so /usr/lib
gcc main.c -ladd
執行時將動態庫(libadd.so)與a.out同時加載到代碼段才能運行。當多個代碼段需要用到一個libXXX時,並不會生成多個libXXX放入代碼段,而是通過共享庫。
當動態庫升級時,以格式為libname.so[.主版本號.次版本號.發行號]命名,如現在將原來的libadd.so修改為libadd.so.1,那怎麽讓原來main.c文件中的add函數還能實現呢?——軟鏈接
先穿插一個概念:
軟鏈接
命令:$ ln -s filename1 filename2
功能: filename2 -> filename1
可以看到當鏈接建立時,file1 -> file,file1的大小為4B,file的大小為739B。可以用過 ls -lh查看鏈接。
軟鏈接存儲是路徑,相當於file1是file的一個快捷方式,所以在查看file1的時候也是顯示file的內容。
回到原來的問題,現在將原來的libadd.so修改為libadd.so.1,只要將libadd.so.1與libadd.so軟鏈接即可。
sudo ln -s libadd.so.1 libadd.so
靜態庫
gcc -c add.c //編譯add.c生成add.o
ar crsv libadd.a add.o //對目標文件*.o進行歸檔,生成lib*.a,將庫文件libadd.a拷貝到/lib或者/usr/lib下(系統默認搜索庫路徑)
gcc -o main main.c -ladd //-ladd表示鏈接庫文件libadd.a/.so
./main
還是用上面同一個例子做測試:
main.c
#include <stdio.h>
int add(int, int);
int main()
{
int j = add(3, 4);
printf("%d\n", j);
return 0;
}
靜態庫是目標文件.a的歸檔文件(格式為libname.a)。如果在編譯某個程序時鏈接靜態庫,則鏈接器將會搜索靜態庫並直接拷貝到該程序的可執行二進制文件到當前文件中;
所以當我們在刪除庫文件中libadd.a後還是可以編譯執行main.c!
靜態庫與動態庫的比較:
? 動態庫只在執行時才被鏈接使用,不是直接編譯為可執行文件,並且一個動態庫可以被多個程序使用故
可稱為共享庫。
? 靜態庫將會整合到程序中,在程序執行時不用加載靜態庫。 因此,靜態庫會使你的程序臃腫並且難以升
級,但比較容易部署。而動態庫會使你的程序輕便易於升級但難以部署。
二者的不同點在於代碼被載入的時刻不同。
- 靜態庫在程序編譯時會被連接到目標代碼中,程序運行時將不再需要該靜態庫,因此體積較大。
- 動態庫在程序編譯時並不會被連接到目標代碼中,而是在程序運行是才被載入,因此在程序運行時還需要動態庫存在,因此代碼體積較小。
Linux下靜態庫和動態庫