靜態庫
先說說我們為什麼需要庫?
當有些程式碼我們大量會在程式中使用比如(scanf,printf等)這些函式我們需要在程式中頻繁使用,於是我們就把這些程式碼編譯為庫檔案,在需要使用時我們直接連結即可。
定義:
程式在編譯
時把靜態庫的程式碼連結到可執行程式中,在程式碼執行時不再需要靜態庫。(簡單理解就是把一堆 .o
檔案打包到一起,當需要用到就讓我們的程式連結進來)
生成及使用方法:
這裡用加減乘除來舉例示意:
//建立所需檔案
[root@localhost ku]# touch add.c add.h sub.c sub.h mul.c mul.h dev.c dev.h main.c
[root@localhost ku]# ls
add.c add.h dev.c dev.h main.c mul.c mul.h sub.c sub.h
[root@localhost ku]#
//編寫所有檔案程式碼
//add.c
#include"add.h"
int add(int x,int y)
{
return x+y;
}
//add.h
#ifndef __ADD_H__
#define __ADD_H__
int add(int x,int y);
#endif // __ADD_H__
//sub.c
#include"sub.h"
int sub(int x,int y)
{
return x-y;
}
//sub.h
#ifndef __SUB_H__
#define __SUB_H__
int sub(int x,int y);
#endif // __SUB_H__
//mul.c
#include"mul.h"
int mul(int x,int y)
{
return x*y;
}
//mul.h
#ifndef __MUL_H__
#define __MUL_H__
int mul(int x,int y);
#endif //__MUL_H__
//dev.c
#include"dev.h"
int dev(int x,int y)
{
return x/y;
}
//dev.h
#ifndef __DEV_H__
#define __DEV_H__
int dev(int x,int y);
#endif // __DEV_H__
//main.c
#include<stdio.h>
#include"add.h"
#include"sub.h"
#include"mul.h"
#include"dev.h"
int main()
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d + %d = %d
",a,b,add(a,b));
printf("%d - %d = %d
",a,b,sub(a,b));
printf("%d * %d = %d
",a,b,mul(a,b));
printf("%d / %d = %d
",a,b,dev(a,b));
return 0;
}
//編譯原始檔
[root@localhost ku]# ls
add.c add.h dev.c dev.h main.c mul.c mul.h sub.c sub.h
[root@localhost ku]# gcc -c *.c //把所有.c檔案生成.o檔案
[root@localhost ku]# ls
add.c add.h add.o dev.c dev.h dev.o main.c main.o mul.c mul.h mul.o sub.c sub.h sub.o
[root@localhost ku]# rm main.o -rf //刪除多餘的.o檔案
[root@localhost ku]# ls
add.c add.h add.o dev.c dev.h dev.o main.c mul.c mul.h mul.o sub.c sub.h sub.o
[root@localhost ku]#
//生成靜態庫
[root@localhost ku]# ar -rc libmycal.a *.o
[root@localhost ku]# ls
add.c add.h add.o dev.c dev.h dev.o libmycal.a main.c mul.c mul.h mul.o sub.c sub.h sub.o
[root@localhost ku]#
//檢視靜態庫
[root@localhost ku]# ls
add.c add.h add.o dev.c dev.h dev.o libmycal.a main.c mul.c mul.h mul.o sub.c sub.h sub.o
[root@localhost ku]# ar -tv libmycal.a
rw-r--r-- 0/0 683 Apr 26 20:46 2018 add.o
rw-r--r-- 0/0 683 Apr 26 20:46 2018 dev.o
rw-r--r-- 0/0 679 Apr 26 20:46 2018 mul.o
rw-r--r-- 0/0 687 Apr 26 20:46 2018 sub.o
[root@localhost ku]#
//連結靜態庫生成可執行檔案
[root@localhost ku]# ls
add.c add.h add.o dev.c dev.h dev.o libmycal.a main.c mul.c mul.h mul.o sub.c sub.h sub.o
[root@localhost ku]# gcc main.c -L. -lmycal
[root@localhost ku]# ls
add.c add.h add.o a.out dev.c dev.h dev.o libmycal.a main.c mul.c mul.h mul.o sub.c sub.h sub.o
[root@localhost ku]#
//執行結果
[root@localhost ku]# ls
add.c add.h add.o a.out dev.c dev.h dev.o libmycal.a main.c mul.c mul.h mul.o sub.c sub.h sub.o
[root@localhost ku]# ./a.out
8 3
8 + 3 = 11
8 - 3 = 5
8 * 3 = 24
8 / 3 = 2
[root@localhost ku]#
以上是整個靜態庫的生成及運用過程
總結起來就3步驟:
首先將原始檔編譯成目標檔案:gcc –c 原始檔
生成靜態庫:ar –rc lib(庫名).a 目標檔案
使用靜態庫:gcc main.c -L(庫的路徑) -l(庫名)
靜態庫的優缺點
優點:
1. 省空間:linker只會複製你用到的objects。
2. 打包簡單。
缺點:
1、如果靜態庫中有全域性變數,那麼在幾個模組中使用,將會導致全域性變數有不同的值,這是非常嚴重的問題。
2、靜態庫編譯時,不會進行連結檢查,所以這麼多靜態庫的問題,在生成靜態庫階段檢查不出來。
3、幾個模組,引用同一靜態庫,如果有一模組沒有編譯到,會引起巨大的差異導致問題。
4.產生大量的庫檔案檔案會佔空間
動態庫
定義:
程式在執行
時才去連結動態庫的程式碼,多個程式共享使用庫的程式碼。
一個與動態庫連結的可執行檔案僅包含他用到的函式入口地址的一個表,而不是外部函式所在目標檔案的機器碼。
生成及使用方法:
事例程式和上面一樣,這裡只寫出操作步驟
[root@localhost ku]# ls
add.c add.h dev.c dev.h main.c mul.c mul.h sub.c sub.h
[root@localhost ku]# gcc -c -fpic *.c
// -fpic 表示編譯為位置獨立的程式碼,不用此選項的話編譯後的程式碼是位置相關的所以動態載入時是通過程式碼拷貝的方式來滿足不同程式的需要,而不能達到真正程式碼段共享的目的。
[root@localhost ku]# ls
add.c add.h add.o dev.c dev.h dev.o main.c main.o mul.c mul.h mul.o sub.c sub.h sub.o
[root@localhost ku]# rm main.o -rf
[root@localhost ku]# ls
add.c add.h add.o dev.c dev.h dev.o main.c mul.c mul.h mul.o sub.c sub.h sub.o
[root@localhost ku]# gcc -shared -o libmycal.so *.o
[root@localhost ku]# ls
add.c add.h add.o dev.c dev.h dev.o libmycal.so main.c mul.c mul.h mul.o sub.c sub.h sub.o
[root@localhost ku]# gcc main.c -L. -lmycal
//-L. 表示要連線的庫在當前目錄中
[root@localhost ku]# ls
add.c add.h add.o a.out dev.c dev.h dev.o libmycal.so main.c mul.c mul.h mul.o sub.c sub.h sub.o
[root@localhost ku]# ./a.out
./a.out: error while loading shared libraries: libmycal.so: cannot open shared object file: No such file or directory
[root@localhost ku]# cp libmycal.so /lib/
//把動態庫移動到系統庫檔案下
[root@localhost ku]# ls
add.c add.h add.o a.out dev.c dev.h dev.o libmycal.so main.c mul.c mul.h mul.o sub.c sub.h sub.o
//執行結果
[root@localhost ku]# ./a.out
8 6
8 + 6 = 14
8 - 6 = 2
8 * 6 = 48
8 / 6 = 1
//第二種方法,更改庫路徑
[root@localhost ku]# ./main
./main: error while loading shared libraries: libmycal.so: cannot open shared object file: No such file or directory
[root@localhost ku]# vim /etc/ld.so.conf.d/mycal.conf //在建立的檔案裡寫上庫的路徑
//寫好路徑之後重新整理緩衝區
[root@localhost ku]# ldconfig
//執行結果
[root@localhost ku]# ./main
8 6
8 + 6 = 14
8 - 6 = 2
8 * 6 = 48
8 / 6 = 1
動態庫優缺點:
優點:
1 .共享記憶體
2 .獨立升級元件(外掛安裝,軟體更新)
3.可以顯示動態載入
缺點:
1.當系統中多個應用程式都用了一個動態連結庫,但是要求的版本不同,這時動態連結庫之間就會相互干擾。
2.效能開銷。動態連結庫為了做到“共享程式碼,但是不共享資料”,引入了不小的開銷,呼叫動態連結庫中的函式,需要好幾次間接記憶體訪問才能走到函式入口,全域性資料也是。