庫:本質上來說是一種可執行代碼的二進制格式,可以被載入內存中執行,分爲靜態庫和動態庫兩類。另外,需要知道的是,由於windows和Linux是兩款操作系統,因此,二者的庫是不兼容的。
靜態函數庫:
後綴通常爲***.a,利用靜態庫編譯的程序有着一定的優點,即編譯後的執行程序不需要外部的函數庫支持,因爲所有使用的函數都已經被編譯進去,但這會造成另外一個問題,如果靜態庫發生改變,程序就需要重新編譯,同時,靜態庫編譯程序生成的文件較大,因爲整個函數庫的所有數據都會被整合進目標代碼中。
利用靜態庫編譯,通常情況下是因爲我們希望我們的程序需要有更好的移植性。
動態函數庫:
後綴通常爲***.so,動態函數庫在編譯的時候並沒有被編譯進目標代碼,只有當程序執行到相關函數時才調用該函數庫裏的相應函數,因此動態函數庫所產生的可執行文件比較小。關於平臺的問題上,如果利用動態庫編譯的程序希望得到運行,那麼該運行環境中必須要有相應的庫來支持,動態函數庫並不影響程序,所以動態函數庫升級更加方便。
二者的最大不同之處在於庫代碼被在於內存的時刻不同,靜態庫通常在編譯時刻就被載入可執行程序,動態庫是在程序運行時載入內存的,編譯過程中只是簡單的引用。
gcc生成靜態鏈接庫實例:
在當前目錄下,有如下幾個文件,Makefile暫不關心。
前三個文件內容如下:
要生成靜態庫文件,首先我們需要將源代碼轉換爲二進制目標文件(hello.c -- > hello.o)
[muhui@bogon mylib]$ gcc -c hello.c -o hello.o
接下來我們需要將hello.o依照靜態庫命名規範【注1】轉化爲靜態庫文件 libmyhello.a
[muhui@bogon mylib]$ ar cr libmyhello.a hello.o
得到靜態庫文件之後,就可以使用gcc命令生成最終目標文件時指明靜態庫名,gcc將會從靜態庫中將共用函數鏈接到目標文件。【注2】
[muhui@bogon mylib]$ gcc -o hello main.c -L. -lmyhello
# -L.指定了靜態庫文件目錄在當前目錄下
完成了gcc編譯的任務之後,我們需要做一件事,來驗證是否我們成功使用了靜態庫。我們嘗試將靜態庫文件刪除,看生成的可執行程序是否還能正確運行。
[muhui@bogon mylib]$ rm -f libmyhello.a
[muhui@bogon mylib]$ ./hello
hello world
程序運行正常,表明靜態庫文件已經被添加進入目標文件。
最後這裏我們留意一下生成的目標文件大小:
[muhui@bogon mylib]$ ll
總用量 652
-rwxrwxr-x. 1 muhui muhui 645220 2月 18 08:44 hello
-rw-rw-r--. 1 muhui muhui 81 2月 17 18:17 hello.c
-rw-rw-r--. 1 muhui muhui 108 2月 17 18:15 hello.h
-rw-rw-r--. 1 muhui muhui 856 2月 18 08:36 hello.o
-rw-rw-r--. 1 muhui muhui 63 2月 17 18:19 main.c
gcc生成動態鏈接庫實例:
同樣還是和上面一樣,使用同一個例子。
動態庫文件依舊需要由.o文件來創建,首先我們清理當前工作目錄。
[muhui@bogon mylib]$ ls
hello hello.c hello.h hello.o main.c Makefile
[muhui@bogon mylib]$ rm -f hello
[muhui@bogon mylib]$ ls
hello.c hello.h hello.o main.c Makefile
這裏保留的hello.o文件,同時也遵守動態庫文件命名規範【注3】,創建動態庫文件libmuhello.so
[muhui@bogon mylib]$ gcc -shared -fPCI -o libmyhello.so hello.o
[muhui@bogon mylib]$ ls
hello.c hello.h hello.o libmyhello.so main.c Makefile
接下來在程序中使用動態庫文件,使用動態庫和使用靜態庫文件方式完全一樣,如下
[muhui@bogon mylib]$ gcc -o hello main.c -L. -lmyhello
[muhui@bogon mylib]$ ls
hello hello.c hello.h hello.o libmyhello.so main.c Makefile
[muhui@bogon mylib]$ ./hello
./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory
報錯!原因說的很清楚,沒有找到動態庫文件。程序運行時,通常還在/usr/lib 和/lib 目錄下查找所需要的動態庫文件,所以這裏我們需要將我們生成的動態庫文件移動到/usr/lib 目錄下(需要root權限)
[muhui@bogon mylib]$ sudo mv libmyhello.so /usr/lib/
[sudo] password for muhui:
[muhui@bogon mylib]$ ls
hello hello.c hello.h hello.o main.c Makefile
[muhui@bogon mylib]$ ./hello
hello world
完成之後,我們再次查看目標文件大小
[muhui@bogon mylib]$ ll
總用量 28
-rwxrwxr-x. 1 muhui muhui 4888 2月 18 09:06 hello
-rw-rw-r--. 1 muhui muhui 81 2月 17 18:17 hello.c
-rw-rw-r--. 1 muhui muhui 108 2月 17 18:15 hello.h
-rw-rw-r--. 1 muhui muhui 856 2月 18 08:36 hello.o
-rw-rw-r--. 1 muhui muhui 63 2月 17 18:19 main.c
兩次對比,就會發現,使用動態庫文件的話,生成的目標文件就會小的多。
這裏需要強調的一點是,如果我們同時生成靜態庫和動態庫文件的話,操作系統一般會優先選擇動態庫。
【注1】靜態庫命名規範:以lib爲前綴,緊接着跟靜態庫名,擴展名爲.a。
【注2】gcc會在靜態庫名前加上lib前綴,然後追加擴展名.a,得到的靜態庫文件名來查找靜態庫文件,注意下面靜態庫名的變化,前綴lib變爲l,同時省略後綴。
【注3】動態庫命名規範:以lib爲前綴,緊接着跟動態庫名,擴展名爲.so
補充一點的是,如果在編譯過程中發現會有報錯產生,很可能是因爲缺少一個叫做glib-static的庫,可以直接使用
yum -y install glibc-static
安裝該文件,推薦直接使用網絡yum源下載,個人嘗試,搭建的本地yum源,安裝失敗,具體原因應該是該庫在鏡像B的問題,這裏不深究。
------muhuizz整理