準備
在linux下,終端完成c/c++的編譯運行,如果使用到靜態庫與動態庫,那麼如何鏈接?這裏以一個例子來完成講述。假如當前位於test目錄,且有a.h、a.c、b.h、 b.c,以及調用a、b中方法的main.c。
每個文件的內容如下
//a.c文件內容如下
#include<stdio.h>
void a(){
printf("The first file a\n");
}
//a.h的內容如下
#ifndef A_H
#define A_H
extern void a();
//b.c文件的內容如下
#include<stdio.h>
void b(){
printf("The second file b\n");
}
//b.h的內容如下
#ifndef B_H
#define B_H
extern void b();
//最後一個main.c是我們的調用文件
int main(int argc,char *argv[]){
a();
b();
return 0;
}
使用靜態庫
首先我們先要將源代碼製作成靜態文件,靜態文件以.a形式結尾,如用的命令ar,例如本例:
gcc -g -c a.c -o a.o //生成.o文件
ar -rc liba.a a.o //形成靜態庫
gcc -g -c b.c -o b.o
ar -rc libb.a b.o
結果如圖所示:
最後一步就是main.c對靜態庫的調用
gcc -g main.c -o main a.a b.a //對靜態庫的調用
./main //運行生成的可執行文件main
結果如圖:
使用動態庫
採用動態庫鏈接的方式,首先需要得到.so結尾的動態鏈接庫,還是以文章開頭的文件爲例
gcc -fpic -shared a.c -o liba.so //a.c生成動態庫liba.c ,動態庫文件一般以lib + 文件名+.so組成
gcc -fpic -shared b.c -o libb.so //同上
然後一樣的通過我們的maic.c對動態庫進行鏈接
gcc main.c -L. -l a b -o main //根據命令規則 lib+文件名+.so,所以這裏只需要指定文件名,-L指定庫文件目錄,.代表當前目錄,-l指定庫文件名。
注意:這裏我們的動態鏈接可能會得到error while loading shared libraries: liba.so: cannot open shared object file: No such file or directory的錯誤。
解決辦法如下:
root用戶下,vim /etc/ld.so.conf ,加入我們自定義庫文件的目錄,我這裏是/root/test,如圖所示
最後得到main文件成功運行
使用動態庫與靜態庫的混合鏈接
這裏我們讓a生成靜態文件liba.a,b生成動態文件libb.so,這兩個文件的生成和前面一樣,我們這裏說如何在main.c中同時對兩種庫鏈接
gcc main.c -L. -Wl,-Bstatic -la -WI,-Bdynamic -lb -o main
注意
-
一定要注意大小寫
-
-Wl,-Bstatic:禁用動態庫
-
-Wl, -Bdynamic :禁用靜態庫
-
如果你的兩套參數和我的相反,一定記得最後再加一個一Wl,-Bdynamic,因爲默認是採用的動態庫,如果禁止了,後面就沒法搞了。
靜態庫與動態庫的區別
兩種鏈接庫的使用我們已經會了,那麼這兩種庫有什麼區別呢?他們分別有什麼優缺點?
靜態庫
在源程序鏈接階段,鏈接器將從庫文件取得所需代碼,複製到生成的可執行文件中在編譯階段完成我們代碼的鏈接,會導致生成的執行文件變大,使用的到的地方都需要加載一份到內存,不方便升級,但是裝載速度快
動態庫
動態庫在鏈接階段沒有被複制到程序中,而是在程序運行時由系統動態加載到內存中供程序調用。動態庫可以實現進程之間資源共享,僅需要裝載到內存一次,升級簡單。但是會減緩裝載的速度,增加程序的依賴性。
總結
好了,我們本文的例子就寫到這裏了,細心的同學可能發現,在這個例子中,如果我們讀某一個文件進行稍微的改動就會導致整個工程掛鉤的文件都需要進行重新編譯,那有沒有什麼辦法避免這樣的麻煩呢?當然有,那就是make 與Makefile,使用make可以避免很多麻煩,他可以自行更改與更新掛鉤的文件,下一篇文章我們就來聊聊make與Makefile