簡述Linux下的靜態庫和動態庫

大雄45發表於2023-02-16
導讀 庫是一種軟體元件技術,庫裡面封裝了資料和函式。庫的使用可以使程式模組化。庫有兩種:靜態庫和動態庫。Windows系統包括靜態連結庫(.LIB檔案)和動態連結庫(.dll檔案)。 通常把庫檔案存放在/usr/lib或/lib目錄下。Linux庫檔名由:字首lib、庫名和字尾3部分組成,其中動態連結庫以.so作為字尾,靜態連結庫通常以.a作為字尾。
1.何為靜態庫和動態庫?

靜態庫(static library, Statically-linked library, LIB)或稱靜態連結庫,是一個外部函式與變數的集合體。靜態庫的檔案內容,通常包含一堆程式設計師自定的變數與函式,在編譯期間由編譯器與聯結器將它整合至應用程式內,並製作成目標檔案以及可以獨立運作的可執行檔案。而這個可執行檔案與編譯可執行檔案的程式,都是一種程式的靜態建立(static build)。其特點是可執行檔案中包含了庫程式碼的一份完整複製;缺點就是被多次使用就會有多份冗餘複製。即靜態庫中的指令全部被直接包含在最終生成的可執行檔案中。

動態庫(Dynamic library, Dynamic-link library, DLL)或稱動態連結庫,是微軟公司在微軟視窗作業系統中實現共享函式庫概念的一種實現方式。動態連結庫可被多個程式同時使用。所謂動態連結,就是把一些經常會共用的程式碼(靜態連結的OBJ程式庫)製作成DLL檔,當程式有需求時函式才進行連結。透過動態連結方式,儲存器浪費的情形將可大幅降低。靜態連結庫則是直接連結到可執行檔案。

一個程式編譯成可執行的步驟:

簡述Linux下的靜態庫和動態庫簡述Linux下的靜態庫和動態庫

靜態庫和動態庫的區別在連結階段如何處理庫,如果將庫連結到目的碼中則是靜態庫,而將庫連結載入推遲到程式執行的時期則是動態庫,可以實現程式之間的資源共享。

2 Linux建立和使用靜態庫

前面已經介紹了靜態庫的概念,下面我們透過一個例項來看靜態庫的使用。

2.1生成靜態庫

1)這裡準備了兩個庫的原始碼st1 、st2用它們來製作庫libmytest.a,如下

簡述Linux下的靜態庫和動態庫簡述Linux下的靜態庫和動態庫

$ 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;
2) 生成libmytest.a檔案

建立靜態庫用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

簡述Linux下的靜態庫和動態庫簡述Linux下的靜態庫和動態庫

2.2使用靜態庫

直接使用

$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

簡述Linux下的靜態庫和動態庫簡述Linux下的靜態庫和動態庫

$ ./test

簡述Linux下的靜態庫和動態庫簡述Linux下的靜態庫和動態庫

這裡gcc的引數-L是告訴編譯器庫檔案的路徑是當前目錄,-l是告訴編譯器要使用的庫的名字叫mytest。

2.3靜態庫總結

在一個標頭檔案中宣告靜態庫所匯出的函式。
在一個原始檔中實現靜態庫所匯出的函式。
編譯原始檔,生成可執行程式碼。
將可執行程式碼所在的目標檔案加入到某個靜態庫中,並將靜態庫複製到系統預設的存放庫檔案的目錄下。
下面透過一個例子來說明:
原始檔: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下的靜態庫和動態庫簡述Linux下的靜態庫和動態庫

在Linux下,可以使用ar命令來建立和修改靜態庫。
這些在linux下man ar一下就可以得到引數,這裡說明幾個常用的

  • d:從庫中刪除成員檔案。
  • r:在庫中加入成員檔案,若存在,則替換。
  • c:建立一個庫。
  • s:無論ar命令是否修改了庫內容,都強制重新生成庫符號表。
  • 其他的命令用時再man。
    【注】gcc -static 檔案.c [-o 檔案]//全部使用靜態庫的方法

    3 Linux建立和使用動態庫

    動態庫的基本概念

    動態庫的基本概念

    1.動態連結庫是程式執行時載入的庫,當動態連結庫正確安裝後,所有的程式都可以使用動態庫來執行程式。動態連結庫是目標檔案的集合,目標檔案在動態連結庫中的組織方式是按照特殊方式形成的。庫中函式和變數的地址是相對地址,不是絕對地址,其真實地址在呼叫動態庫的程式載入時形成。

    2.動態連結庫的名稱有別名(soname), 真名(realname)和連結名(linker name)。別名由一個字首lib,然後是庫的名字,再加上一個字尾“.so”構成("libxxx.so")。真名是動態連結庫真實名稱,一般總是在別名的基礎加上一個小版本號,釋出版本等構成。除此之外,還有一個連結名,即程式連結時使用的庫的名字。

    3.在動態連結庫安裝的時候,總是複製檔案到某個目錄下,然後用一個軟連線生成別名,在庫檔案進行更新的時候,僅僅更新軟連結即可。

    下面我們透過一個例項來學習如何生成動態庫和使用動態庫。

    3.1生成動態庫

    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
3.2使用動態連結庫

在編譯程式時,使用動態連結庫和靜態庫是一致的,使用”-l庫名”的方式,在生成可執行檔案的時候會連結庫檔案。使用如下命令:

$ gcc -o test main.c -L. -ltest
$ ls -l

簡述Linux下的靜態庫和動態庫簡述Linux下的靜態庫和動態庫

這裡 -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

我們可以看一下結果:

簡述Linux下的靜態庫和動態庫簡述Linux下的靜態庫和動態庫

$ ./test

也能得到正確結果。

簡述Linux下的靜態庫和動態庫簡述Linux下的靜態庫和動態庫

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重新整理即可。

3.3動態庫總結

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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章