**:
最近慢慢將開發環境轉向了 freebsd ,漸漸的發現了許多東西跟 windows 下不太一樣。我指的是,跟我以前想當然的理解不太一樣。比如,unix 下對動態鏈結庫 so 的處理,和 windows 下的 dll 就不太相同。
之前,我對 windows 下更為了解一些。早幾年做 windows 開發,老是為動態鏈結,靜態鏈結這些問題糾纏不清;慢慢的才有了比較清晰的理解,現在基本上不會為這類問題困繞了。前段時間,碰到一些朋友寫 lua 的擴充套件庫(windows 版本)時遇到的幾個 bug ,就是因為鏈結問題導致的。公司內部的乙個專案,在伺服器程式上也碰到了錯誤鏈結 lua 引起的 bug ,在內部 maillist 上爭論了好久。當時,作為 windows 程式設計師,跟同事中的 unix 程式設計師爭論看似相同的問題時,卻老說不到一起去;今天才發現,原來是相互之間對動態鏈結庫的理解不同導致的。
今天,寫下本文,或許可以讓以後跨平台開發的朋友少走點彎路。
動態鏈結庫在 unix 下,習慣以 .so 為檔名結尾(通常還以 lib 開頭)。而 windows 下是以 .dll 為檔案字尾。windows 在處理 dll 上還有一些細節容易被人忽略,我曾經為這個寫過一篇 blog。
如果需要執行時主動載入乙個動態鏈結庫,windows 下可以使用 loadlibrary 這個 kernel api (在 kernel32.dll 中);unix 下是用 dlopen 。windows 下找到 dll 中匯出符號的位址,可以用 getprocaddress ,而 unix 也有對應的 api ...
這些相互對應的 api ,似乎預示著對等的功能,但事實上是有區別的。
dll 事實上和 exe 檔案一樣,同屬 pe 格式的執行檔案。對於隱式的引用外部符號,需要把外部符號所在的位置寫在 pe 頭上。pe 載入器將從 pe 頭上找到依賴的符號表,並載入依賴的其它 dll 檔案。
但是,unix 上並非如此,so 檔案大多為 elf 執行檔案格式。當它們需要的外部符號,可以不寫明這些符號所在的位置。也就是說,通常 so 檔案本身並不知道它依賴的那些符號在哪些 so 裡面。這些符號是由呼叫 dlopen 的程序執行時提供的。而 unix 下的執行檔案本身會暴露自己靜態鏈結的符號,(可以是自己本身實現的,或者是從靜態庫 .a 檔案裡鏈入的)。dlopen 將把這些符號通報給 dlopen 載入的 .so 檔案,最終完成動態鏈結。(事實上 dlopen 還可以指定 mode ,完成更複雜的操作)
因為這個區別,unix 下的 lua 直譯器可以完全靜態鏈結所有的 lua api ;我們為 lua 擴充套件的庫,以 so 的形式存在被執行時載入不會有任何隱患。而 windows 下,必須生成乙個 luacore 的 dll 檔案,由 lua 直譯器於擴充套件庫共享 lua api (還包括 crt 的實現) 才不會出問題。
也因為這個區別,vc 下才會有讓 windows 開發新手困惑不解的動態鏈結 crt ,靜態鏈結 crt ,多執行緒庫,單執行緒庫,等等的選項。沒點點 windows 開發功力的人,多少都要在上面栽幾個跟頭。
從動態鏈結庫的這個設計上來看,我個人感覺,windows 弄的真是糟糕透頂。尤其是對開發者來說是這樣。至少我們在 windows 下做乙個 dll 檔案給大家使用還需要攜帶乙個 .lib 檔案;而 unix 下一般只需要有相應的標頭檔案就夠了。對於編寫新的 .so ,找不到的符號可以就讓它在那裡,直到最終執行檔案來把所有需要的符號聯合到一起。windows 可以存在乙個 dll 對另乙個 dll 的隱式依賴;而 unix 下一般不需要讓 so 和 so 有隱式依賴關係。這讓我們全域性替換類似 crt 的東西變的困難許多;而以我自己的程式設計經驗來看,好處卻沒有多少。
順便一提的是 unix 下需要用 ldconfig 來管理動態庫,這比 windows 下 copy dll 到當前目錄下就可以用的方式,無疑提高了系統的安全性。
linux下的靜態庫和動態庫
庫是什麼?在我們實際程式設計中,經常會引入各種庫函式,那麼庫是什麼?從本質上來說是一種可執行 的二進位制格式,可以被載入記憶體中執行。庫分靜態庫和動態庫兩種。靜態庫 linux下靜態庫的名字一般是lib a,為庫的名字。利用靜態函式庫編譯成的檔案比較大,因為整個函式庫的所有資料都會被整合進目標 中,...
linux下的靜態庫和動態庫
意義 為了避免 的重寫率,我們可以將已經寫好的 形成乙個庫,當我們再次用到的時候可以直接呼叫,而不是重新去寫,即 站在巨人的肩膀上 linux下有兩種庫 一 靜態庫 準備工作 int swap int x,int y include int main 1 將我們需要的函式生成乙個.o 檔案 root...
Linux下的靜態庫和動態庫
在我們平時寫 的時候,通常會引用一些庫檔案來幫助我們實現需要的功能,這些庫檔案是別人提前已經寫好的,我們只需要拿出庫檔案的介面來使用就可以了。這種庫檔案分為兩種,一種是靜態庫,一種是動態庫。靜態庫可以簡單的看成一組目標檔案集合,即很多目標檔案經過壓縮打包後形成乙個檔案。在靜態庫的載入過程中,第一步是...