簡述Linux下的靜態庫和動態庫
導讀 | 庫是一種軟體元件技術,庫裡面封裝了資料和函式。庫的使用可以使程式模組化。庫有兩種:靜態庫和動態庫。Windows系統包括靜態連結庫(.LIB檔案)和動態連結庫(.dll檔案)。 通常把庫檔案存放在/usr/lib或/lib目錄下。Linux庫檔名由:字首lib、庫名和字尾3部分組成,其中動態連結庫以.so作為字尾,靜態連結庫通常以.a作為字尾。 |
靜態庫(static library, Statically-linked library, LIB)或稱靜態連結庫,是一個外部函式與變數的集合體。靜態庫的檔案內容,通常包含一堆程式設計師自定的變數與函式,在編譯期間由編譯器與聯結器將它整合至應用程式內,並製作成目標檔案以及可以獨立運作的可執行檔案。而這個可執行檔案與編譯可執行檔案的程式,都是一種程式的靜態建立(static build)。其特點是可執行檔案中包含了庫程式碼的一份完整複製;缺點就是被多次使用就會有多份冗餘複製。即靜態庫中的指令全部被直接包含在最終生成的可執行檔案中。
動態庫(Dynamic library, Dynamic-link library, DLL)或稱動態連結庫,是微軟公司在微軟視窗作業系統中實現共享函式庫概念的一種實現方式。動態連結庫可被多個程式同時使用。所謂動態連結,就是把一些經常會共用的程式碼(靜態連結的OBJ程式庫)製作成DLL檔,當程式有需求時函式才進行連結。透過動態連結方式,儲存器浪費的情形將可大幅降低。靜態連結庫則是直接連結到可執行檔案。
一個程式編譯成可執行的步驟:
靜態庫和動態庫的區別在連結階段如何處理庫,如果將庫連結到目的碼中則是靜態庫,而將庫連結載入推遲到程式執行的時期則是動態庫,可以實現程式之間的資源共享。
前面已經介紹了靜態庫的概念,下面我們透過一個例項來看靜態庫的使用。
1)這裡準備了兩個庫的原始碼st1 、st2用它們來製作庫libmytest.a,如下
$ ls -l $ cat st1.c #includevoid print1()printf("Hello!I am st1!\n "); $ cat st2.c #includevoid print2()printf("Hello!I am st2!\n"); $ cat main.c #includeint main(int argc, const char *argv[])print1();print2();return 0;
建立靜態庫用ar ,它將很多.o轉換成.a
$ gcc -c st1.c st2.c $ ar crs libmytest.a st1.o st2.o $ ls -l $ file libmytest.a
靜態庫檔案libmytest.a已經生成,用file 檢視其屬性,發現它確實是歸檔壓縮檔案。用ar -t libmytest.a可以檢視一個靜態庫包含了那些obj檔案:
$ ar -t libmytest.a
直接使用
$gcc -o test main.c libmytest.a
雙L連結法
$gcc -o test main.c -lmytest -L.(庫所在目錄,.表示當前目錄)
單L連結法(需要配置環境變數LIBRARY_PATH,把庫放在所在目錄配置)
$gcc -o test main.c -lmytest
前面我們已經寫好了main.c,現在測試一下
$ gcc -o test main.c -L. -lmytest $ ls -l
$ ./test
這裡gcc的引數-L是告訴編譯器庫檔案的路徑是當前目錄,-l是告訴編譯器要使用的庫的名字叫mytest。
在一個標頭檔案中宣告靜態庫所匯出的函式。
在一個原始檔中實現靜態庫所匯出的函式。
編譯原始檔,生成可執行程式碼。
將可執行程式碼所在的目標檔案加入到某個靜態庫中,並將靜態庫複製到系統預設的存放庫檔案的目錄下。
下面透過一個例子來說明:
原始檔:mylib.c
#includevoid welcome(void)printf("welcome to libmylib\n");
1>編譯mylib.c生成目標檔案:
$gcc -o mylib.o -c mylib.c
2>將目標檔案加入到靜態庫中:
$ar -rcs libmylib.a mylib.o
【注】庫檔名以lib開頭,以.a結尾
3>將靜態庫copy到Linux的庫目錄(/usr/lib或者/lib)下:(也可以不複製,注意配置環境變數)
$sudo cp libmylib.a /usr/lib/libmylib.a //管理員身份
編寫呼叫庫函式的測試程式test.c:
#includeint main(void)printf("create and use library:\n");welcome();return 0;
4>使用靜態庫編譯:
$gcc -o test test.c -lmylib
這裡注意,編譯時無需帶上字首和字尾。
5>執行可執行程式test:
$./test
在Linux下,可以使用ar命令來建立和修改靜態庫。
這些在linux下man ar一下就可以得到引數,這裡說明幾個常用的
- d:從庫中刪除成員檔案。
- r:在庫中加入成員檔案,若存在,則替換。
- c:建立一個庫。
- s:無論ar命令是否修改了庫內容,都強制重新生成庫符號表。
其他的命令用時再man。
【注】gcc -static 檔案.c [-o 檔案]//全部使用靜態庫的方法
動態庫的基本概念
動態庫的基本概念
1.動態連結庫是程式執行時載入的庫,當動態連結庫正確安裝後,所有的程式都可以使用動態庫來執行程式。動態連結庫是目標檔案的集合,目標檔案在動態連結庫中的組織方式是按照特殊方式形成的。庫中函式和變數的地址是相對地址,不是絕對地址,其真實地址在呼叫動態庫的程式載入時形成。
2.動態連結庫的名稱有別名(soname), 真名(realname)和連結名(linker name)。別名由一個字首lib,然後是庫的名字,再加上一個字尾“.so”構成("libxxx.so")。真名是動態連結庫真實名稱,一般總是在別名的基礎加上一個小版本號,釋出版本等構成。除此之外,還有一個連結名,即程式連結時使用的庫的名字。
3.在動態連結庫安裝的時候,總是複製檔案到某個目錄下,然後用一個軟連線生成別名,在庫檔案進行更新的時候,僅僅更新軟連結即可。
下面我們透過一個例項來學習如何生成動態庫和使用動態庫。
1)當前資料夾下有下面四個檔案
$ ls -l
檔案內容分別為:
$ cat mylib.h #ifndef _MYLIB_H_#define _MYLIB_H_#includevoid print1();void print2();#endif $ cat dy1.c #include "mylib.h"void print1()printf("My first shared lib!\n"); $ cat dy2.c #include "mylib.h"void print2()printf("My second shared lib!\n"); $ cat main.c #include "mylib.h"int main(int argc, char *argv[])print1();print2();return 0;
2)這裡我們將dy1.c與dy2.c用來建立動態庫
$ gcc -fPIC -Wall -c dy1.c dy2.c $ gcc -shared -o libtest.so dy1.o dy2.o
這裡 -fPIC 建立與地址無關的編譯程式,-shared指定生成動態連結庫。
我們也可以一步到位
$ gcc -o libtest.so -fPIC -shared dy1.c dy2.c
我們可以看到下面已經生成了一個libtest.so
$ ls -l
在編譯程式時,使用動態連結庫和靜態庫是一致的,使用”-l庫名”的方式,在生成可執行檔案的時候會連結庫檔案。使用如下命令:
$ gcc -o test main.c -L. -ltest $ ls -l
這裡 -L 指定動態連結庫的路勁,-ldtest連結庫函式test 。-ltest是動態庫的呼叫規則。
下的動態庫命名方式是lib*.so,而在連結時表示位-l*,*是自己命名的庫名。
我們可以看到這裡已經生成了test可執行檔案,我們可以執行一下:
$ ./test
可以發現發生了錯誤,這是因為程式執行時沒有找到動態連結庫造成的。程式編譯時連結動態庫和執行時使用動態連結庫的概念是不同的,在執行時,程式連結的動態連結庫需要在系統目錄下才行。
這就到了動態庫的路徑問題,有三種方法:
1)把庫複製到/usr/lib和/lib目錄下:
$ sudo cp libtest.so /lib
【注】這裡要超級使用者許可權sudo
我們看一下執行結果:
$ ./test
這裡執行結果正確。
2)在 LD_LIBRARY_PATH 環境變數中加上庫所在路徑
$ export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH
我們可以看到:libtest.so 的路徑已經存在
$ ldd test
我們可以看一下結果:
$ ./test
也能得到正確結果。
3)新增/etc/ld.so.conf.d/*.conf檔案。把庫所在的路徑加到檔案末尾,並執行ldconfig重新整理。
$ cd /etc/ld.so.conf.d/ $ ls $ sudo vi my.conf $ cat my.conf /home/bruceou/demo/libtest.so
在/etc/ld.so.conf.d/下建立my.conf 裡面只有一句/home/bruceou/demo/libtest.so即libtest.so的路徑,然後執行ldconfig重新整理即可。
1.編譯動態庫
方法一:
命令:
gcc -fPIC -Wall -c .c
命令:
gcc -shared -o lib.so .o
方法二:
命令:
gcc .c .c .c -fPIC -shared -o lib.so
2.安裝路徑
命令:
cp lib.so /usr/lib/lib.so//管理員身份
3.動態庫的連結
命令:
gcc -o .c -L. -l
或者:
命令:gcc .c -L. -l -o
4.執行可執行程式
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2935425/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- linux下的靜態庫與動態庫Linux
- android下java的靜態庫和動態庫AndroidJava
- ios靜態庫和動態庫iOS
- [Linux]動靜態庫Linux
- Linux共享庫、靜態庫、動態庫詳解Linux
- linux下靜態連結庫和動態連結庫的區別有哪些Linux
- cmake:生成靜態庫和動態庫
- iOS動態庫和靜態庫的運用iOS
- linux 動態庫 靜態庫 函式覆蓋Linux函式
- 靜態庫與動態庫
- iOS中的動態庫,靜態庫和framework介紹iOSFramework
- 一、靜態庫和動態庫,Makefile專案管理專案管理
- 動靜態庫
- Android NDK祕籍--淺析靜態庫和動態庫Android
- 靜態庫和動態庫的製作以及Bundle資原始檔的使用
- 動態連結庫與靜態連結庫
- Linux 靜態庫生成及呼叫Linux
- 封裝動態庫dll與靜態庫lib(原理及簡單例項)封裝單例
- Linux動態庫Linux
- 關於MNN工程框架編譯出來的靜態庫和動態庫的使用框架編譯
- 筆記: 判斷lib庫是動態庫還是靜態庫筆記
- Linux環境下:程式的連結, 裝載和庫[靜態連結]Linux
- CMake和靜態庫順序
- 靜態庫生成
- Android NDK祕籍--編譯靜態庫、呼叫靜態庫Android編譯
- Linux下快速靜態編譯Qt以及Qt動態/靜態版本共存Linux編譯QT
- 偽靜態、靜態和動態的區別
- iOS的Framework靜態庫iOSFramework
- C靜態庫的建立與使用--為什麼要引入靜態庫?
- iOS 靜態庫 與私有庫iOS
- Android:JNI與NDK(二)交叉編譯與動態庫,靜態庫Android編譯
- iOS - 靜態庫.a 和 framework 詳解iOSFramework
- 動態庫的建立和呼叫
- 靜態資源公共庫
- iOS中動/靜態庫支援bitcode的問題iOS
- 編譯靜態庫的方式使用spdlog和fmt編譯
- 靜態路由和動態路由路由
- 靜態代理和動態代理