一.靜態庫和動態庫的簡單介紹緩存
程序設計的模塊化是人們一直在追求的目標,由於當一個系統十分複雜的時候,將系統模塊化既能夠並行開發,又能夠加強程序的可用性,下降程序間的耦合度。在一個複雜的多模塊系統中,app
各個模塊編譯完成後,會生成各自的目標文件*.o,最後經過連接器將各個模塊連接起來生成可執行文件。模塊化
庫其實就是一個模塊文件。人們爲了將一些功能模塊提供給他人使用,同時又不想將源代碼直接分發給別人(也多是不須要,畢竟庫使用更方便,不用從新編譯),就將功能模塊作成庫,函數
外部應用經過連接庫來加載庫的功能模塊。好比glibc是GNU標準的C標準函數庫。spa
庫有靜態和動態之分。靜態庫在編譯時被連接進可執行文件中,動態庫是在程序運行時連接。靜態庫的優勢是使用方便,只要編譯時連接成功,在程序運行時就不會有找不到庫或者庫錯亂的設計
問題,可是這也形成了升級更新困難和內存空間浪費的問題。對於靜態庫來講,升級就必須從新編譯應用程序連接靜態庫而後所有升級,並且若是多個應用程序都用到了同一個靜態庫,那麼當多個內存
應用程序運行時,內存中就會有靜態庫的多個拷貝,十分浪費空間。由於這些緣由,動態庫應運而生。動態庫是程序運行時才連接,因此在程序更新時,咱們只須要更新動態庫文件,從新啓動應用開發
程序就會連接新庫,並且當內存中已經有一個動態庫的拷貝時,其餘應用在運行時,若是須要連接庫,會先從內存中查找庫,找到後就直接連接該庫,找不到再加載庫到內存中,這保證了不會有同源碼
一個庫的多個拷貝在內存中佔用空間。io
二.靜態庫和動態庫的編譯和連接
2.1 程序源碼
咱們將會建立一個app,主要功能是輸出「hello world」,具體實如今庫libhello.a/libhello.so中實現。下面是各個文件的源代碼:
app源碼
#include<stdlib.h>
#include<stdio.h>
#include"hello.h"
void main(void)
{
hello();
hello();
}
庫源碼
hello.c源碼
#include<stdlib.h>
#include<stdio.h>
void hello(void)
{
printf("\n======hello world======\n");
}
hello.h源碼
#ifndef HELLO_H
#define HELLO_H
void hello(void);
#endif
2.2.靜態庫的編譯和連接
第一步:生成目標文件
# gcc -c hello.c
生成目標文件hello.o
第二步:編譯生成靜態連接庫libhello.a
# ar rcs libhello.a hello.o
第三步:增長用於外部調用靜態庫函數的頭文件hello.h
hello.h頭文件的做用是給外部調用庫函數提供函數聲明
第四步:外部程序使用靜態庫
在app.c中包含所用靜態庫函數聲明的頭文件hello.h
生成app.o的目標文件
#gcc -c app.c
連接靜態庫libhello.a生成可執行文件app
#gcc -o app app.o -L. -lhello
執行app
#./app
======hello world======
======hello world======
2.3.動態庫的生成
一樣是先生成目標文件hello.o,而後編譯動態庫文件libhello.so
# gcc -shared -fPCI -o libhello.so hello.o
# ls
發現libhello.so已經生成了,而後咱們開始生成可執行文件。這裏動態庫並無連接。
# gcc -o app app.o -L. -lhello
編譯經過,執行app時出錯
#./app
./app: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
程序運行時,找不到動態庫。那爲何編譯時能經過呢?由於編譯時的-L指定了編譯路徑,因此編譯能經過,可是在運行加載動態庫時,會默認從/lib,/usr/lib路徑下去找,而實際庫不在該路徑下,因此加載失敗。
解決的辦法有三個:
1.將庫文件拷貝到默認的動態庫路徑/lib,/usr/lib,此爲最簡單,最快捷的方法
2.程序編譯時指定動態庫路徑,使用「-Wl,-rpath」。
# gcc -o app app.o -L. -lhello -Wl,-rpath=/mnt/hgfs/share/workspace/demo/LibraryDemo1
注意:有的系統中多是"-Wl,-rpath,/path/to/dir",使用時須要注意。還有就是我本身在使用時出現的小問題,提醒下你們,我開始老是寫成-Wl,rpath=path,結果編譯怎麼都不過,老是提示找不打rpath=path這個文件或路徑,後來才發現少寫了個「-」,提醒你們須要認真看錯誤提示。
3.就是更改/etc/ld.so.conf。查看/etc/ld.so.conf發現它包含了/etc/ld.so.conf.d目錄下的全部*.conf。到/etc/ld.so.conf.d/目錄下,
新建一個*.conf,在裏面加上動態庫的路徑(你也能夠直接在其中某一個conf中增長一條,可是最好不要這麼幹,不然之後可能有未知的混亂)。
此時運行app仍然失敗,緣由是系統查找動態庫是經過查找/etc/ld.so.cache緩存,僅僅更改配置是不行的,還須要更新緩存。此時能夠經過/sbin/ldconfig更新緩存。
# /sbin/ldconfig
有時候想知道動態庫路徑是否加入到緩存中,可使用ldconfig指令
# sudo /sbin/ldconfig -p |grep path
在執行更新緩存後,能夠查看到:
# libhello.so (libc6) => /mnt/hgfs/share/workspace/demo/LibraryDemo1/libhello.so
以上三種方法親測可用。