在linux環(huán)境下編程,我們?nèi)绻胍褂玫谌降膸?,基本上有以下幾種方式。
1、將第三方庫的源碼合并到我們的工程項目代碼中,一起編譯。
2、將第三方庫編譯成靜態(tài)庫(xxx.a),我們在使用時,在Makefile中引用該靜態(tài)庫。
3、將第三方庫編譯成動態(tài)庫(xxx.so), 我們在使用時,隱性調(diào)用該動態(tài)庫,具體表現(xiàn)為需要 在程序中包含動態(tài)庫的 頭文件,同時需要在/usr/lib路徑下,存放動態(tài)庫文件,以便程序調(diào)用。
4、將第三方庫編譯成動態(tài)庫(xxx.so), 我們在使用時,顯性調(diào)用該動態(tài)庫,在程序中,不需要包含動態(tài)庫的頭文件,使用 dlopen、dlsym等接口函數(shù)調(diào)用該動態(tài)庫。
在上述四種方式中:
第 1 和 2 種,本質(zhì)上是一樣的,使用靜態(tài)庫,編譯時,會將靜態(tài)庫的內(nèi)容合并到工程代碼中,唯一區(qū)別的是當(dāng)我們拿不到第三方庫的源碼時,可以直接使用靜態(tài)庫,相當(dāng)于使用一個黑盒子,靜態(tài)庫提供接口。
第 3 和 4 種方式,我們常用的是第3種方式,也就是隱性調(diào)用,但是顯性調(diào)用一種程序插件的概念,隨用隨加載,不用不加載。
顯性調(diào)用和隱性調(diào)用區(qū)別
名稱使用方式動態(tài)庫文件內(nèi)存其他隱性調(diào)用引用動態(tài)庫頭文件需要提前拷貝到/usr/lib/目錄,否則程序無法執(zhí)行程序開始執(zhí)行,不管是否用到動態(tài)庫功能,都會將動態(tài)庫讀到內(nèi)存中不會額外調(diào)用插件庫顯性調(diào)用不需要引用動態(tài)庫頭文件,但是需要引用不一定,如果程序不會執(zhí)行到動態(tài)庫功能,則不需要拷貝,即便使用,也可以使用絕對路徑來使用,不需要拷貝到/usr/lib/目錄下只有程序執(zhí)行到dlopen時,才會將動態(tài)庫讀入內(nèi)存會額外調(diào)用linux插件庫,來支持顯性調(diào)用。
在使用dlopen時,編譯時候要加入 -ldl (指定dl庫),若dl庫有問題,那么在運行時調(diào)用dlopen時會出現(xiàn)段錯誤。因此要保證dl庫沒問題。
開發(fā)時遇到一個問題,本地需要編寫一個so庫給應(yīng)用程序提供接口,在應(yīng)用程序中使用dlopen來打開so庫,但是運行時調(diào)用dlopen時出現(xiàn)段錯誤。
原因是應(yīng)用程序編譯時引用應(yīng)用程序中l(wèi)ib下的dl庫,該庫有問題導(dǎo)致運行時出現(xiàn)段錯誤。解決方式就是把應(yīng)用程序中l(wèi)ib下的dl庫給替換掉。
小結(jié)
顯性調(diào)用更多的是體現(xiàn)在“插件”的思想,使用起來更加靈活,比如大的工程項目中,同樣一套代碼,提供不一樣的功能時,為了節(jié)省內(nèi)存、磁盤容量,可以按需加載。在使用方式上,顯性調(diào)用相比隱性調(diào)用,略復(fù)雜,需要增加額外的轉(zhuǎn)換代碼,而隱性調(diào)用,只需要包含動態(tài)庫頭文件,在代碼中,直接調(diào)用API即可。在生產(chǎn)程序中,如果對內(nèi)存或磁盤、啟動速度沒有嚴(yán)苛的要求,盡量使用隱形調(diào)用,方便程序編寫和維護(hù)。