開發環境:
CentoOs(Linux )
起因:
最近在項目開發過程中需要生成.so文件來給其他的程序調用,而我的這部分程序又需要調用其他的.so,這對於一個剛剛入職的程序猿來說着實有些令人着急,大致的項目需要如圖,其中libStd.so是項目的標准庫,和我的.so在同一父目錄下,libmkl_xxx.so是mkl庫,在系統目錄下。
當時由於是第一次生成.so(年少無知),照着網上的代碼直接就編譯了,然后其他同事在使用時出現undefined symbol <something>.
錯誤代碼:
g++ -c -g -fPIC Dir1/*.cpp Dir2/*.cpp -I/opt/intel/mkl/include g++ -shared -o libMyLib.so *.o
概念:
函數庫可以分成動態庫(dynamic)和靜態庫(static),靜態庫相當於把你的所有文件都打了包,以后要跟其他程序集成的話就得把整個包給集成進去,這往往導致最終程序會變得很大,而且也不易升級、維護,動態庫相當於一個開放的包,大家都可以用,只要你鏈接到它,你也可以用,我鏈接到之后我也可以用,是公共、獨立的。兩者更進一步的區別參考鏈接【1】在不同系統上這兩者命名稍微有些不同:
(后綴) | Windows | Linux |
靜態庫 | .lib | .a |
動態庫 | .dll | .so |
.so文件是shared object文件,即共享對象,也就是說其在加載后是可以被多個進程所共享,至於如何實現可以參考鏈接【2】。
-fPIC: Position Independent Code,參見鏈接【2】
-shared:表示產生的是共享對象
由於在鏈接產生共享對象的時候需要檢查語法和語義,所以在鏈接階段需要指定鏈接的庫名-l和庫所在位置-L【1】(這也是我出現上面的錯誤的原因)
解決方案:
g++ -c -g -fPIC Dir1/*.cpp Dir2/*.cpp -I/opt/intel/mkl/include g++ -shared -o libMyLib.so *.o -lStd -L../PATH_A/TO/Bin -lmkl_xxx -L/PATH_B/TO_MKL_XXX
后續:
為了查看自己生成的庫鏈接對不對,可以使用
ldd MyLib
這條指令用於查看依賴項,即你的庫有沒有鏈接成功
可以看到上面的libBarbeque.so沒有找到,這是為什么的?我明明在鏈接階段指定了對應的.so才對?先別急,這是因為你雖然剛剛指定庫,但是系統在查找時默認只會在當前路徑或者系統指定的LD_LIBRARY_PATH目錄下查找,所以你只需要把依賴的.so放到當前目錄下,或者用配置環境變量的方式使系統知道你需要在哪里找,可以參考鏈接【3】(記得是修改LD_LIBRARY_PATH不是默認的PATH!)
最后注意,在實際運行的時候也需要指定對應的庫和路徑,在LD_LIBRARY_PATH中添加.so所在文件夾,這樣可以確保程序順利調用
【1】http://blog.csdn.net/nieyinyin/article/details/6890557:linux中的.so和.a文件
【2】http://www.cnblogs.com/cswuyg/p/3830703.html:linux共享對象之編譯參數fPIC
簡要提綱(僅供自己觀看,有理解不對的請諒解!)
1.如果不采用PIC,相當於給每個進程開專線,這樣物理內存利用率不高;PIC在我認為就是建立了一個中轉站,大家先來中轉站,再轉到對應的模塊;
【3】http://www.cnblogs.com/hust-chenming/p/4943268.html:linux查看和修改PATH環境變量的方法