動靜態庫
靜態庫(.a):程式在編譯連結的時候把庫的程式碼連結到可執行檔案中。程式執行的時候將不再需要靜態庫,但是,多個程式使用相同的靜態庫時,每個程式都會包含一份庫的程式碼,可能會導致可執行檔案體積較大。
動態庫(.so):是在程式執行時被載入的庫。當一個程式連結了動態庫,在程式啟動時,作業系統的動態連結器會載入所需的動態庫到記憶體中。多個程式可以共享同一個動態庫的程式碼段,這有助於減少記憶體的佔用。
庫
庫的本質就是.o
檔案的集合。我們有如下的兩個原始檔,如果我們不想給對方我們的原始碼,那麼就可以給對方提供.o檔案(可重定位二進位制目標檔案),和標頭檔案。對方就可以用它的程式碼來連結我們的.o
檔案,使用我們提供的方法。(.o
檔案提供方法,.h
檔案說明都有什麼方法)
將多個文.o
件打包形成一個檔案,這其實就是庫。根據打包方式的不同,就可以分為靜態庫和動態庫。
靜態庫
透過ar [選項] [靜態庫檔名] [目標檔案列表]
命令建立或更新靜態庫。
-r
:將目標檔案插入到靜態庫中。如果靜態庫中已經存在同名的目標檔案,則替換它。-c
:建立靜態庫檔案時,不顯示建立過程的詳細資訊。如果靜態庫不存在,則建立它;如果已經存在,則更新它 。
如上就透過ar
命令形成了一個靜態庫檔案。但是這個檔案並不能直接連結形成可執行檔案,因為這個檔案並沒有包含標頭檔案。我們之所以能夠在系統上執行我們的程式,是因為C語言已經給我們提供了對應的標頭檔案和庫檔案。
如上,我們已經將標頭檔案和.a
檔案打包,此時只需要將這個包發給別人就可以了。
使用靜態庫
-
第一種方法
此時打包好的庫檔案和原始檔在同一個目錄下,當我們使用
gcc
進行編譯的時候,它仍然報錯,提示標頭檔案找不到。但是我們不是已經有標頭檔案了嗎?那是因為在搜尋標頭檔案的時候,編譯器會在當前路徑下搜尋或在系統預設指定路徑下搜尋。當前路徑是指和原始碼處在同一級的路徑,而這裡.h
檔案的路徑太深了。想要成功的編譯連結形成一個可執行檔案。我們還需要三個選項,分別是
-I
,-L
,-l
。-I
:指明標頭檔案的位置。-L
:指明庫檔案的位置。-l
:指明庫名稱。(庫名稱是指去掉字首和字尾所剩下的部分,如libmymath.a
去掉前字尾後只剩下mamath
)
此時就成功形成了可執行檔案。我們在來看一下下面這張圖:
這裡不對啊!我明明是靜態庫,但是為什麼顯示的是動態連結呢?這是由於
gcc
預設是動態連結的,當你編譯連結形成可執行檔案時,你不僅僅使用了你自己的靜態庫,你還用了C語言提供的動態庫,只要使用了動態庫,那麼gcc
就會選擇預設的動態連結,儘管你提供的是靜態庫。 -
第二種方法
第二種方法就是直接將標頭檔案和庫檔案放到對應的系統指定的路徑下。標頭檔案放到
/usr/include
目錄下,庫檔案放到/usr/lib64
目錄下。但是編譯的時候仍然要加上-l
選項,也就是指定庫的名稱。(這種方法並不推薦)
動態庫
建立動態庫
使用 gcc
編譯器並帶上 -fPIC
(Position-Independent Code,位置無關程式碼)選項將原始檔編譯成目標檔案(.o
檔案)。
gcc -fPIC -c my_sub.c
gcc -fPIC -c my_add.c
接著,使用 gcc
編譯器的 -shared
選項,基於之前生成的目標檔案來建立動態庫。
gcc -shared -o libmymath.so my_add.o my_sub.o
如此,就建立了一個動態庫。
使用動態庫
與靜態庫一樣,要使用這個動態庫,就要將標頭檔案和這個庫同時給其他人。將動態庫與自己的程式編譯連結形成可執行檔案的方法與靜態庫一樣。
gcc -o my_math main.c -I mylib/include/ -L mylib/lib/ -l mymath
但是當你執行形成的可執行檔案的時候,會發現他報錯了,顯示這個庫找不到。我們不是已經將標頭檔案和庫檔案的位置都告訴它了嗎,為什麼還是找不到呢?
這是因為你只將庫的路徑告訴了gcc
,所以gcc
編譯連結的時候沒問題。但是我們現在是在執行程式,執行的時候已經和gcc
沒有關係了,之和作業系統有關。而對於作業系統你並沒有指明庫的路徑。
指明路徑
給作業系統指明庫的路徑有以下幾種方法。
-
將路徑新增到
LD_LIBRARY_PATH
環境變數中。export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/wzh/studyCode/my_lib/test/mylib
此時再執行程式就可以正常執行了。但是這個方法只是臨時的,一旦退出,下次想要正常執行就要重複這個操作。
-
將庫新增到
usr/lib64
目錄下。這個方法是永久有效的,但是不推薦。
-
更改
/etc/ld.so.conf.d/
下的配置檔案。首先在
/etc/ld.so.conf.d/
下建立一個檔案,然後再將庫所在的路徑寫入到該檔案中(當然不建立也可以,隨便將庫路徑寫入到該目錄下的任意檔案中)。最後還要執行sudo ldconfig
這條命令,配置檔案才能生效。如此,這個路徑就永久有效了。
-
建立軟連結
在和執行檔案同級的目錄下建立一個庫檔案的軟連結(也可以將這個連結直接建立在
/usr/lib64
目錄下)。如下ln -s /home/wzh/studyCode/my_lib/test/mylib/lib/libmymath.so libmymath.so
像這樣,程式同樣可以正常執行。