c 靜態庫與動態庫

2021-08-08 05:15:09 字數 3811 閱讀 2027

庫分為靜態庫,動態庫,在不同系統下字尾不同。

2.1.1 在鏈結和執行階段都涉及庫的呼叫(訪問)。.h檔案(標頭檔案)是庫的介面。.h檔案提供給庫的使用者,使用者通過.h來呼叫庫中的api。

2.1.2 庫中包含的是函式的實現(一堆函式的實現),這些函式在編寫的時候同樣要包含1中的標頭檔案,然後生成庫。

2.1.3 有了介面,函式就知道去包含這些介面的庫中尋找實現的**,找這些庫就需要知道庫的名字,所在的位置(路徑),否則程式只能通過編譯,在鏈結的時候會出現問題。這些資訊都是在makefile中給出的。-l 後面跟的是庫的路徑 -l後邊跟的是庫的「核心」名字。完整的庫名字,比如libtest.so(動態庫)、libtest.a(靜態庫),其核心名字為test、test,即在makefile中鏈結庫的時候需要去掉完整名字的首尾部。

2.2.1 makefile生成庫的指令:

(1)靜態庫(生成libtest.a)

add_static:

ar -rcs libtest.a add.o

add.o:

gcc -c -fpic -ggdb add.cpp          # (debug調模式)

gcc -c -fpic -os add.cpp            # (release發布模式)

中間檔案是add.o,最後生成的靜態庫名字是libtest.a

(2)動態庫(libtest.so)

add_share:    gcc -shared -o ../bin/libtest.so ../project_makefile/*.o  # (*.o  包含了 add.o)

add.o:

gcc -c -fpic -ggdb add.cpp          # (debug調模式)

gcc -c -os -fpic add.cpp            # (release發布模式)

中間檔案是add.o,最後生成的靜態庫名字是libtest.so

2.2.2 由庫生成可執行檔案的過程

(1)由靜態庫生成

test_static:

g++ -o teststatic test.cpp -l ../lib -l test

靜態庫生成可執行檔案test_static,test_s中會包含靜態庫的**。檔案會比較大。

(2)由動態庫生成

test_dynamic:

g++ -o testdynamic test.cpp -l ../bin -l test

-l 設定的路徑將被優先搜尋,然後才是搜尋系統的環境變數中的路徑,比如/usr/lib 等路徑。

動態庫生成可執行檔案test_dynamic的時候,test_dynamic中不好含庫的**,在執行的時候再去找這個庫。故檔案體積比較小。

在可執行檔案執行的過程中,需要通過配置環境變數找到動態庫,並載入動態庫檔案。(-l 是在鏈結的過程中庫的路徑,鏈結動態庫生成可執行檔案過程,是在可執行檔案中記錄對動態庫的引用,因此這裡會尋找一次動態庫生成乙個記錄放在可執行檔案中。等到執行時候會通過這個記錄去尋找動態庫,而尋找的路徑需要配置環境變數給出)

(1)在/etc/ld.so.conf 中新增搜尋路徑

直接在/etc/ld.so.conf 中新增路徑,或者在/etc/ld.so.conf.d/ 目錄下(sudo)新建乙個.conf檔案,然後將絕對路徑新增進去。

執行sudo /sbin/ldconfig 命令。ldconfig ,簡單的說,它的作用就是將/etc/ld.so.conf列出的路徑下的庫檔案快取到/etc/ld.so.cache 以供使用。

(2)在環境變數 ld_library_path 中指明庫的搜尋路徑。

設定方式:     

export ld_library_path=/opt/gtk/lib:$ld_library_path

export ld_library_path=$ld_library_path:/usr/local/

可以用下面的命令檢視 ld_libray_path 的設定內容:

echo $ld_library_path
這種方式只能在當前終端起作用,如果新開啟乙個終端就不會起作用了。

(3)修改~/.bashrc 中的環境變數

vim ~/.bashrc

source ~/.bashrc # 使得修改內容生效

同樣.cpp中要留有標頭檔案(.h)這個介面,或者在.cpp檔案中直接給出目錄,或者在makefile中用-i指定。

.cpp中不能出現main()函式,makefile檔案中必須包含子動態庫的目錄和名字,用 -shared -fpic 等命令

一步生成即可,因為子動態庫就相當於.o檔案。如果要分步生成,需要規定好哪一步用 -i 指定頭檔案目錄,哪一步鏈結子動態庫的再做研究。

(1)生成動態庫

gcc test_a.c test_b.c test_c.c -fpic -shared -o libtest.so
(2)一步生成可執行檔案        

g++  mutiply.cpp -shared -fpic -o libmul.so  -i /home/wyz/桌面/ku -l /home/wyz/桌面/ku -l test  # 鏈結了標頭檔案,以及子動態庫
注:子動態庫中的函式不能直接被主函式呼叫,若想用此子動態庫中的函式,需要主函式直接鏈結這個子動態庫。

首先。.h  檔案是對庫中函式的宣告。.h在.c檔案中是展開的過程。現有a.out a.c,b.so、b.h ,c.so 、c.h 5個檔案,a.out-->b.so c.so;b.so-->c.so其中,如果b.so要想用c.so中的函式,就要在b.so中 #include「c.h」也就是先宣告要使用的函式,保證gcc在編譯這一步可以通過;然後在makefile中 -l c.so,保證ldd在鏈結這一步可以通過。

然後。a.c中如果想用c中的庫有兩種方式:

<1>通過b鏈結,這時需要在b.so的標頭檔案b.h中包含c.h,即#incldue「c.h」,這樣在a.c編譯的時候,會將b.h展開一次,再將其包含的c. h再展開,這樣就對b.so和c.so中的函式進行了宣告,gcc編譯通過,即a.c可以用c庫中的函式了。然後在生成程序a.out的makefile中必須把b.so c.so 都鏈上,這樣ldd通過,即成功鏈結成了a.out。最後,在執行a.out時候要把b.so 和c.so都放到環境變數指定的目錄中。

<2>單獨呼叫c庫,在a.c 中直接包含c.h,即inculde"c.h",同樣在鏈結成a.out中的makefile中鏈結上c.so

其次。在a.c中如果只用b.so中的函式,需要在a.c中 include「 b.h」這時候gcc編譯會通過;然後在ldd(鏈結)這一步,在鏈結成a.out的makefile中把b.so 和c.so都連線上。最後在執行a.out的時候同樣要把所有動態庫都放到環境變數指定的目錄中。

# makefile 中

-wl-rpath-link

-werror

-static

# shell 中

ldd       # 檢視檔案依賴哪些動態庫 ldd  a.out   或者ldd libtest.so

C 靜態庫與動態庫

感覺比較形象,就摘過來了.這次分享的 宗旨是 讓大家學會建立與使用靜態庫 動態庫,知道靜態庫與動態庫的區別,知道使用的時候如何選擇。這裡不深入介紹靜態庫 動態庫的底層格式,記憶體布局等,有興趣的同學,推薦一本書 程式設計師的自我修養 鏈結 裝載與庫 庫是寫好的現有的,成熟的,可以復用的 現實中每個程...

C 靜態庫與動態庫

庫是寫好的現有的,成熟的,可以復用的 現實中每個程式都要依賴很多基礎的底層庫,不可能每個人的 都從零開始,因此庫的存在意義非同尋常。本質上來說庫是一種可執行 的二進位制形式,可以被作業系統載入記憶體執行。庫有兩種 靜態庫 a lib 和動態庫 so dll 所謂靜態 動態是指鏈結。回顧一下,將乙個程...

C 靜態庫與動態庫

1.靜態庫 1.靜態庫實際上就是一些目標檔案 一般以.o結尾 的集合,靜態庫一般以.a結尾,只用於生成可執行檔案階段。2.在鏈結步驟中,鏈結器將從庫檔案取得所需 複製到生成的可執行檔案中。這種庫稱為靜態庫。其特點是 可執行檔案中包含了庫 的乙份完整拷貝,在編譯過程中被引導程式中。缺點就是多次使用就會...