1. 什么是庫
庫是寫好的現有的,成熟的,可以復?的代碼。現實中每個程序都要依賴很多基礎的底層庫,不可能 每個?的代碼都從零開始,因此庫的存在意義?同尋常。 本質上來說庫是?種可執?代碼的?進制形式,可以被操作系統載?內存執?。庫有兩種:
? 靜態庫 .a[Linux]、.lib[windows]
? 動態庫 .so[Linux]、.dll[windows]
2. 靜態庫
在當前目錄下,有以上兩個我們寫的.h文件和對應的.c文件。在test文件當中包含了我們使用的頭文件,如果我們希望test文件編譯鏈接形成可執行文件,直接gcc的話則會報錯!
我們先把所有的.c文件編譯形成.o文件,然后再鏈接所有的.o文件就可以形成可執行文件了。?
所以我們可以得出結論結論:所有的庫【動態庫、靜態庫】其本質都是源文件對應的.o文件!
不過,我們寫的庫終究還是要給別人使用,如果我們每次都是把許多.o文件給別人,讓別人鏈接這么多的.o文件,那這也太麻煩了,所以在Linux中,我們有一個轉門針對這個問題的打包命令ar【archive 、r 是 gnu 歸檔?具, rc 表? (replace and create)】?靜態庫的本質就是.o打了一個包。
假設在張三目錄下,我們需要用到我們設計的庫,那我們可以我們的庫打包拷貝給他,并同時把我們的頭文件拷貝給他,這樣張三就可以更方便的使用了。
需要解釋一下指令gcc -o test test.c -L . -l myc中的選項,-L表示在哪個路徑下找庫【編譯器默認在路徑/usr/lib64查找庫】,-l表示我們要找的庫的名字。對于庫名libmyc.a來說前綴lib和后綴.a是固定的,myc表示真實有效的命名。如果我們要連接所有的非C/C++標準庫【包括外部或我們自己寫的】,都需要指明-L和-l。不過,如果我們將這些庫提前安裝【也就是拷貝】到系統當中,其實我們也不需要指明路徑了。其實,還有一個-I選項來指明我們需要的頭文件,只不過這里默認在當前路徑下找就不需要特殊指明了。
3. 動態庫
下面簡單制作了一個Makefile文件方便動態庫的生成打包和垃圾文件的清理。
可以看到,在操作方面和靜態庫相比,不同的地方在于,我們都是使用gcc編譯器,形成.o文件時,我們需要增加一個選項-fPIC,在打包文件時,我們需要增加一個選項-shared【動態庫也叫共享庫】。?
? shared:表??成共享庫格式
? fPIC:產?位置?關碼(position independent code),這里先不解釋。
? 庫名規則:libxxx.so
下面我已經把打包好的動態庫和頭文件拷貝給張三目錄下,我們編譯鏈接動態庫可以成功生成可執行文件test,但是在執行該文件時卻發生了問題:找不到動態庫!
?test所依賴的libmyc.so庫果然沒有找到。
解釋:當我們在編譯形成可執行文件時,我們只告訴了編譯器gcc我們的動態庫在哪里,叫什么,而并沒有讓系統知道我們的動態庫在哪里叫什么!而可執行文件在運行時,需要知道動態庫的路徑和名字。
那這里就有一個問題了:為什么靜態庫在編譯鏈接形成可執行后,就可以直接運行了,沒有找不到庫的問題????
那是因為,靜態庫在編譯鏈接時就把靜態庫文件拷貝到了可執行文件當中,當我們運行時就不再依賴庫了,程序直接加載到內存當中就可以運行。而動態庫在形成程序加載到內存當中運行時,依然需要找到對應的動態庫!
解決辦法:
>系統會默認在指定路徑下【一般來說在這個路徑/lib64/】尋找對應的庫文件,所以最簡單粗暴的方法就是把我們的動態庫拷貝到對應的路徑【系統安裝動態庫】下。
>第二種方法就是給我們的庫在系統路徑下建立軟鏈接,讓軟鏈接執向我們的庫。
>第三種做法就是導環境變量的方法:系統不僅會在默認的路徑下尋找動態庫,還會根據環境變量中的LD_LIBRARY_PATH路徑下尋找動態庫,所以我們可以把我們庫的路徑導入到這個環境變量中。
>第四種做法就是修改相關的配置文件,先看操作:
我們將動態庫所在的路徑拷貝到文件/etc/ld.so.conf.d/mylib.conf中,其中,文件mylib.conf是我們自己隨便新建的。
接下來,我們完成這個命令即可:【要?效,這里要執行ldconfig,重新加載庫搜索路徑】
4. 一些小問題
上面,我們初步了解了我們什么是動靜態庫以及它們的生成和使用的相關操作,下面有一些小問題。
>如果我們為程序同時提供動靜態庫,編譯器會怎么做呢?
答:gcc/g++編譯器會默認使用動態庫!
>那如果,我們非要使用靜態庫鏈接,如何辦到呢?
答:在編譯時帶上-static選項!不過,如果沒有靜態庫,編譯時則會報錯!