所謂靜態庫,就是在靜態編譯時由編譯器到指定目錄尋找並且進行鏈接,一旦鏈接完成,最終的可執行程序中就包含了該庫文件中的所有有用信息,包括代碼段、數據段等。所謂動態庫,就是在應用程序運行時,由操作系統根據應用程序的請求,動態到指定目錄下尋找並裝載入內存中,同時需要進行地址重定向。 win32平台下,靜態庫通常后綴為.lib,動態庫為.dll linux平台下,靜態庫通常后綴為.a,動態庫為.so 從本質上來說,由同一段程序編譯出來的靜態庫和動態庫,在功能上是沒有區別的。不同之處僅僅在於其名字上,也就是“靜態”和“動態”。 由上面的介紹不難看出,相對於動態庫,靜態庫的優點在於直接被鏈接進可執行程序中,之后,該可執行程序就不再依賴於運行環境的設置了(當然仍然會依賴於 CPU指令集和操作系統支持的可執行文件格式等硬性限制)。而動態庫的優點在於,用戶甚至可以在程序運行時隨時替換該動態庫,這就構成了動態插件系統的基礎。 具體使用靜態庫和動態庫,由程序員根據需要自己決定。
另外,需要說明的一點是,從底層實現上,動態庫的效率可能會比靜態庫稍差一點點,注意,這里用了“可能”二字,具體差不差,還得看寫程序的人。之所以可能會差,主要原因在於,程序總無法直接調用動態庫中的函數符號,而只能通過調用操作系統的runtime enviroment接口來動態載入某個函數符號,同時獲得該函數符號在內存中的地址,將其保存為函數指針進行調用,這就在函數調用時增加了一次間接尋址的過程。
還是那句話,希望大家都能深入opencv源碼庫中去,不要僅僅滿足於會調幾個API,這樣很難對自己有提高的。深入進去讀源碼,看看人家是怎么組織軟件架構的,怎么划分模塊的。實際上,如果任何一個軟件體系的層次模塊划分足夠清晰和靈活的話,移植性就不會成為很大的問題,無非就是字節對齊、部分算法利用特殊指令集進行優化之類的,這些改動應該僅限於局部調整,而不用全盤重寫的。軟件架構,很重要的一條就是open-close 原則,要清楚哪些是可變的哪些是不可變的。就像上面,將來會發生變化的算法,就可以考慮放到動態庫中,以免將來程序統一全部升級。
另外,在移植軟件的過程中,保持接口不變是有多重含義的,我們通常知道的是:
- 函數、變量名稱不變
- 函數、變量語法屬性不變(比如一個聲明為C形式的函數,必須以C形式對其進行調用,否則由於重載特性會找不到函數名)
- 函數返回值類型不變
- 函數參數個數不變
- 函數參數類型不變
這里,常常被人們遺忘的,也是最重要的一點是:
保持函數語義不變
這是什么意思,對於一段程序,除了詞法分析、語法推導之外,還有很重要的一條就是語義分析。簡單來說,對於一個函數,必須保持移植前后,該函數的返回值含義不變、參數含義不變、函數內部行為的外部表現不變。忽視其中任意一條,都會造成上層應用程序的行為變為未定義,從而移植失敗。
