1. 程式人生 > >linux c/c++ 動態庫和靜態庫的生成與使用

linux c/c++ 動態庫和靜態庫的生成與使用

二.介紹
     從原始碼到可執行程式,通常要經過最重要的兩大步是:編譯,連結。編譯就是將原始檔生成中間檔案的過程,在linux下就是生成  .obj檔案。連結就是用連結器將,這些個中間檔案有序地”糅合“在一起,構成一個可執行檔案。通常,一個.c檔案或者.cpp原始檔編譯後,就會對應生成一個.obj檔案。           那麼庫檔案是什麼東西呢?其實庫檔案就是將這些中間檔案.obj進行打包生成的檔案。那麼為什麼要將這些obj檔案打包成庫檔案呢?一個很重要的原因是,方便程式碼複用。通常,我們都會有自己寫的一些公用的函式,一般是一些工具類的函式。然後再不同的專案中,經常會引用到這些公用的函式。顯而易見的做法是,將公用函式的.h檔案和.cpp檔案分別丟到某個專案的.h檔案目錄或.cpp檔案目錄中,編譯的時候也跟對待其他的原始檔一樣呼叫g++或者gcc進行編譯。如果是引用的第三方檔案不多還好,要是使用到了一些大型的第三方庫比如zlib,openssl等,那麼編譯這些庫都得花很長的時間。      那麼那些懶的程式設計師就想到了一個辦法,只編譯一次,並將這些第三方庫編譯後生成的中間檔案全部保留下來,下次可以直接用了。那麼又來了個問題,加入某個第三方庫有許多原始檔,那豈不是要儲存好多.obj檔案??至少看起來,目錄都是亂糟糟的。因此,就想到了一個辦法將這些個.obj檔案打包起來放在一起,也就產生了所謂的庫檔案。      連結的時候又有問題了,如果這些第三方庫很大或者很多,直接將專案自己的中間檔案跟第三方庫檔案連結成可執行程式,最終這個程式一定非常臃腫,挺佔空間。而且關鍵是,執行程式的時候,會將程式丟到記憶體裡去,那麼如果多個程式同時呼叫了這些第三方庫,那麼在記憶體裡,可能會存在兩份第三方庫的拷貝,貌似挺佔記憶體。好的,聰明的程式設計師又想到好辦法了,生成動態庫,連結的時候不會將第三庫檔案”糅合“進可執行程式中,程式佔的硬碟變小了。第二,當程式執行時,會將第三方庫丟進記憶體中,但是如果有多個程式也動態連結了這個第三方庫,記憶體中只會有一份拷貝,也就是多個程式共享一個第三方庫,哈,記憶體佔用解決了。 三.製作庫檔案      1,製作靜態庫檔案           使用linux下的ar命令可以打包中間檔案生成靜態庫檔案。通過man ar檢視ar的具體用法。一般可以使用 ar -crv 來產生靜態庫。比如:           g++ -g -c add.cpp  生成add.o           g++ -g -c sub.cpp  生成sub.o           ar -crv libmymth.a add.o sub.o生成歸檔檔案,也就是我們的靜態庫檔案。      2 ,製作動態庫檔案           g++ -fPIC -g -c add.cpp 生成add.o           g++ -fPIC -g -c sub.cpp 生成sub.o           -fPIC選項是為了生成與地址無關的編譯程式,這樣讓中間檔案能夠在多個程式中共享           g++ -shared -o libmymath.so add.o sub.o 生成相應的動態庫           或者直接合成一步:           g++ -shared -fPIC -o libmymath.so add.cpp sub.cpp  四.使用庫檔案     動態庫或者靜態庫都可以在連結的時候,使用 -l 進行連結。但是要注意的是,-l 選項只會在特定的目錄裡去尋找指定的庫檔案。這些特定的目錄指的是 /usr/lib,還有$LD_LIBRARY_PATH指定的路徑,還有ld.so.cache中的快取內容。其中ld.so.cache是通過ldconfig命令來生成的,改命令會讀取 /etc/ld.so.conf檔案中的目錄列表,並寫入ld.so.cache檔案中。      因此常規的做法是,將生成的庫檔案直接丟到 /usr/lib下,或者放到$LD_LIBRARY_PATH的某一個目錄中,或者再/etc/ld.so.conf中配置庫檔案所在的目錄。這樣連結器就可以找到庫檔案。      特別的,對於動態庫。程式在執行的時候還會尋找動態庫檔案,如果連結的時候存在動態庫而執行的時候不存在動態庫,也會報錯。靜態庫就不一樣,只要連結的時候存在庫檔案就行了,應為庫檔案和其他中間檔案一起打包進了最終的二進位制檔案。      例子:           假設你把生成的庫檔案放到了上述連結器可以找到的地方,那麼你可以這樣連結你的程式:                g++ -o main main.o -lmymath             另外g++提供了一個 -L選項用來指定庫檔案的目錄,例如假設你的庫檔案放在了 /root/data/lib下,那麼你可以這樣連結你的程式:                g++ -o main main.o -L/root/data/lib -lmymath           這樣連結後生成的程式,如果是連結了靜態庫,就可以直接正常執行。但是如果是連結的動態庫,那麼在執行程式的時候,通常都會報錯顯示找不到動態庫。原因上面已經提過了,連結的時候指定了動態庫的目錄,但是執行的時候沒有指定動態庫的目錄,解決的辦法是,將動態庫丟到連結器搜尋的目錄下。 參考: