Linux静态库和动态库学习总结
一、廢話
之前由于工作需要,要封裝一個Linux加密解密轉換的動態庫,這個之前只做過Windows下面的,Linux下面還真沒有做過,之后做了整一個晚上才算做好,不過其中也學到了不少東西,包括Linux下的動態庫和靜態庫,MakeFile等等。之前就已經寫了一個練習,之后怕又忘了,總結一下備忘,以后也好查。
很大部分內容都是收集的一些東西還有自己學習的體會,有什么錯誤或者問題請直接提出。
二、關于庫的問題
1.庫的原則
現實中每個程序都要依賴很多基礎的底層庫,不可能每個人的代碼都從零開始。盡量不重復做別人已經做過的事,就是盡量充分利用別人的勞動成果。就是“站在巨人的肩膀上”做事情。
2.庫的種類
根據鏈接時期的不同,庫又有:靜態庫和共享庫(動態庫)
二者的不同點在于代碼被載入的時刻不同
靜態庫的代碼在編譯過程中已經被載入可執行程序,因此體積較大
共享庫的代碼是在可執行程序運行時才載入內存的,在編譯過程中僅簡單的引用,因此代碼體積較小。
3.靜態庫和動態庫的比較
接靜態庫其實從某種意義上來說只不過它操作的對象是目標代碼而不是源碼而已。因為靜態庫被鏈接后庫就直接嵌入可執行文件中了,這樣就帶來了兩個問題。
(1)首先就是系統空間被浪費了。這是顯而易見的,想象一下,如果多個程序鏈接了同一個庫,則每一個生成的可執行文件就都會有一個庫的副本,必然會浪費系統空間。
(2)再者,一旦發現了庫中有bug,挽救起來就比較麻煩了。必須一一把鏈接該庫的程序找出來,然后重新編譯。
而動態庫的出現正彌補了靜態庫的以上弊端。因為動態庫是在程序運行時被鏈接的,所以磁盤上只須保留一份副本,因此節約了磁盤空間。如果發現了bug或要升級也很簡單,只要用新的庫把原來的替換掉就行了。
但是靜態庫也有自己的優點:
編譯后的執行程序不需要外部的函數庫支持,因為所有使用的函數都已經被編譯進去了。
靜態庫的名字一般是libxxx.a(Linux)
動態庫的名字一般是libxxx.so (Linux),有時候也是 libxxx.so.major.minor,xxxx是該lib的名稱,major是主版本號, minor是副版本號
linux系統有幾個重要的目錄存放相應的函數庫,如/lib /usr/lib
4.如何判斷一個程序有沒有鏈接動態庫
(1)file命令
file程序是用來判斷文件類型的,啥文件一看都清楚明了。
(2)ldd命令
看動態庫,如果目標程序沒有鏈接動態庫,則打印“not a dynamic executable” (不是動態可執行文件)
<file :run和run_dyn都是可運行文件,action.h上一個ASCII C++文件>
<ldd: run_dyn 使用了共享庫,action.o是不動態可執行文件>
?
5.linux下庫文件是如何產生的
(1)靜態庫
靜態庫的后綴是.a,它的產生分兩步
Step 1.由源文件編譯生成一堆.o,每個.o里都包含這個編譯單元的符號表
Step 2.ar命令將很多.o轉換成.a,成文靜態庫
(2)動態庫
動態庫的后綴是.so,它由gcc加特定參數編譯產生。
三、我的學習例子
1.要用到的工具
g++/gcc
ar
gcc常用參數
-L 加載庫文件路徑
-l 指明庫文件名字
-fPIC 達到動態鏈接的目的,還有一個什么要注意的,忘了
-I dir選項的功能,在頭文件的搜索路徑列表中添加 dir 目錄
2.我的文件
(1)doThing
//dosomething.h
1: #ifndef DOSOMETHING_H 2: #define DOSOMETHING_H 3: 4: #include <string> 5: 6: void doThing(const std::string& strThing); 7: 8: #endif // DOSOMETHING_H 9://dosomething.cpp
1: #include "dosomething.h" 2: #include<iostream> 3: 4: void doThing(const std::string& strThing) 5: { 6: std::cout << "start do thing :" << strThing << std::endl; 7: } 8:(2)Action類,使用doThing函數
//action.h
1: #ifndef ACTION_H 2: #define ACTION_H 3: #include<string> 4: 5: using namespace std; 6: 7: class Action 8: { 9: public: 10: void setAction(const string& strAction); 11: void doAction(void); 12: 13: private: 14: string mstrAction; 15: }; 16: 17: #endif // ACTION_H 18://action.cpp
1: #include "action.h" 2: #include "dosomething.h" 3: 4: void Action::setAction(const string& strAction) 5: { 6: mstrAction = strAction; 7: } 8: 9: void Action::doAction(void ) 10: { 11: doThing(mstrAction); 12: } 13:(3)主文件
//main.cpp
1: #include <iostream> 2: #include "action.h" 3: 4: int main(int argc, char **argv) 5: { 6: 7: Action action; 8: action.setAction("say hello!"); 9: action.doAction(); 10: 11: return 0; 12: } 13:?
linux下生成寫庫文件代碼好像更容易些,不用寫Windows下面那樣的在頭文件還要要寫DLL導出,顯得很干凈。
3.使用靜態庫的方法
基本命令:
g++ –c –o –L –l -I
ar cr 打包
最后生成了run,可以直接執行成功。
4.使用動態庫
基本命令:
g++ –c –o –shared –fPIC –L –l –I
生成so時加 –shared –fPIC
我在生成后立即執行有錯誤了。
原因:因為在動態函數庫使用時,會查找/usr/lib、/lib目錄下的動態函數庫,而此時我們生成的庫不在里邊。
這個時候有好幾種方法可以讓他成功運行:
(1)最直接最簡單的方法就是把so拉到/usr/lib或/lib中去,但這好像有點污染環境吧?
(2)export LD_LIBRARY_PATH=$(pwd)
(3)可以在/etc/ld.so.conf文件里加入我們生成的庫的目錄,然后/sbin/ldconfig
關于/etc/ld.so.conf
/etc/ld.so.conf里面存放的是鏈接器和加載器搜索共享庫時要檢查的目錄,默認是從/usr/lib /lib中讀取的,所以想要順利運行,我們也可以把我們庫的目錄加入到這個文件中并執行/sbin/ldconfig 。
關于/etc/ld.so.cache
/etc/ld.so.cache里面保存了常用的動態函數庫,且會先把他們加載到內存中,因為內存的訪問速度遠遠大于硬盤的訪問速度,這樣可以提高軟件加載動態函數庫的速度了。
使用了第(2)種方法解決問題
四、其它涉及到的東西
(1)dlopen方法的動態庫顯式調用
(2)gcc的各個參數
(3)makefile的編寫
五、感謝
學習過程中參考了好多其它文章,由于之前存的TXT參考,無法查找出處給出鏈接,在這里謝謝作者,這里僅供本人學習。
您可以對本文隨意轉載修改或使用,但請保持正確性,不要誤導他人。
本文出處:http://pppboy.blog.163.com/blog/static/302037962011112104720934/
總結
以上是生活随笔為你收集整理的Linux静态库和动态库学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用python实现远程复制 (scp +
- 下一篇: linux上很方便的上传下载文件工具rz