Apache HTTP Server 版本 2.4
Apache HTTP Server 是個模組化程式,其中管理者可以在挑選一系列模組時選擇要在伺服器中納入哪些功能。模組會編譯為與主程式 httpd
二進位檔案分開存在的動態共享物件 (DSO)。DSO 模組可以在建立伺服器時編譯,或者,它們可以在稍後使用 Apache 延伸工具 (apxs
) 編譯和新增。
或者,模組可以在建立伺服器時,靜態編譯至 httpd
二進位檔案中。
文件描述如何使用 DSO 模組及其使用原理。
相關模組 | 相關指令 |
---|---|
提供個別 Apache httpd 模組載入功能的 DSO 支援,基於名為 mod_so
的模組,該模組必須靜態編譯至 Apache httpd 核心。除了 core
之外,它是唯一無法自己放入 DSO 的模組。實務上,所有其他已發行的 Apache httpd 模組都將會放入 DSO 中。在將模組編譯成名為 mod_foo.so
的 DSO 之後,您可以使用 mod_so
在您的 httpd.conf
檔案中載入此模組,以便在伺服器啟動或重新啟動時載入此模組。
可以透過 configure
的 --enable-mods-static
選項來停用個別模組的 DSO 版本,正如 安裝文件中所探討的。
為了簡化為 Apache httpd 模組 (特別是對於第三方模組) 建立 DSO 檔案的動作,提供了一個稱為 apxs
(APache eXtenSion) 支援程式。它可以用來建立 在 Apache httpd 原始碼樹之外的 基於 DSO 的模組。其概念很簡單:當安裝 Apache HTTP Server 時,configure
的 make install
程序會安裝 Apache httpd C 程式庫標頭檔,並且將建置 DSO 檔案時平台依賴的編譯器和連結器旗標放入 apxs
程式中。如此一來,使用者就可以使用 apxs
來編譯他的 Apache httpd 模組原始碼,而且不需要 Apache httpd 配發的原始碼樹,也不必與平台依賴的編譯器和連結器旗標費神糾纏,就能進行 DSO 支援。
為了讓您大致了解 Apache HTTP Server 2.x 的 DSO 功能,請參閱以下簡潔的摘要
建置並安裝 分散式 Apache httpd 模組,例如 mod_foo.c
,到自己的 DSO mod_foo.so
$ ./configure --prefix=/path/to/install --enable-foo
$ make install
設定 Apache HTTP Server 並啟用所有模組。只有基礎模組組會在伺服器啟動期間載入。您可以透過在 httpd.conf
中啟用或停用 LoadModule
指令,變更已載入的模組組。
$ ./configure --enable-mods-shared=all
$ make install
有些模組只對開發者有用,而且不會建置。當使用 all 模組組時。如要建置包含開發者模組在內的所有可用模組,請使用 reallyall。此外,所有已建置模組的 LoadModule
指令都可以透過設定選項 --enable-load-all-modules
啟用。
$ ./configure --enable-mods-shared=reallyall --enable-load-all-modules
$ make install
apxs
建置並安裝 第三方 Apache httpd 模組,例如 mod_foo.c
,到自己的 DSO mod_foo.so
在 Apache httpd 原始碼樹之外$ cd /path/to/3rdparty
$ apxs -cia mod_foo.c
在所有情況下,一旦共用模組編譯完畢,您必須在 httpd.conf
中使用 LoadModule
指令,告訴 Apache httpd 啟動模組。
請參閱 apxs 文件,深入瞭解更詳細的資訊。
在現代的 Unix 衍生系統上,存在一種稱為動態連結/載入 動態共用物件 (DSO) 的機制,它提供一種方式來製作程式碼區塊的特殊格式,以便在執行階段將其載入可執行程式的位址空間。
此載入作業一般可用兩種方式完成:在可執行程式啟動時,由稱為ld.so
的系統程式自動進行;或於執行中的程式內,透過對 Unix 載入器的編程系統介面,藉由系統呼叫dlopen()/dlsym()
手動載入。
以第一種方式載入時,DSO 通常稱為「共享程式庫」或「DSO 程式庫」,且檔案名稱為libfoo.so
或libfoo.so.1.2
。DSO 會儲存在系統目錄 (通常為/usr/lib
) 中,並在建置期間,透過對連結器指令指定-lfoo
,建立至可執行程式的連結。如此會將程式庫的參考硬編碼至可執行程式檔,才能使 Unix 載入器在啟動時,於/usr/lib
中找到libfoo.so
,或是在透過連結器選項 (如-R
) 編碼的路徑中找到,或是在由環境變數LD_LIBRARY_PATH
設定的路徑中找到。接著載入器將解決可執行程式 (且尚未解決) 中,DSO 內可用的任何符號。
可執行程式中的符號,通常不會由 DSO 參考 (因為 DSO 是通用程式碼的可重複使用程式庫),所以無須進行進一步的解決。可執行程式無須執行任何程式碼,即可使用 DSO 中的符號,這是因為完整的解決作業已由 Unix 載入器執行完畢。(事實上,呼叫ld.so
的程式碼是執行期間啟動程式碼的一部分,此程式碼會連結至每個已非靜態繫結的可執行程式) 動態載入共同程式庫程式碼的優點十分明顯:程式庫程式碼只需儲存一次,載入至libc.so
等系統程式庫中,並為每個程式節省磁碟空間。
以第二種方式載入時,DSO 通常稱為「共享物件」或「DSO 檔」,且可以套用任意副檔名 (但正規名稱為foo.so
)。此類檔案通常保持在程式特定的目錄中,不會自動建立至執行中的程式 (程式使用 DSO 時)。相反地,可執行程式會在執行期間,經由dlopen()
將 DSO 手動載入至其地址空間中。在此階段不會為可執行程式解決 DSO 的任何符號。不過,Unix 載入器會自動根據可執行程式及已載入的 DSO 程式庫 (特別是來自無所不在的libc.so
中所有符號) 匯出的符號集合,解決 DSO 中 (且尚未解決) 的任何符號。如此一來,DSO 會得知可執行程式的符號集合,就如同它當初已與此程式庫靜態連結一般。
最後,為了利用 DSO 的 API,可執行程式必須透過 dlsym()
來解析 DSO 中特定的符號,以便稍後在調度表中使用。換句話說:可執行程式必須手動解析它需要的所有符號,才能夠使用它。這種機制的優點是不需要的程式部分無需載入(因此不耗用記憶體),直到該程式需要時。根據需要,這些程式部分可以在動態載入時延伸基礎程式的功能。
雖然此 DSO 機制聽起來很簡單,但是至少有一個困難步驟:當使用 DSO 來延伸程式時(第二種方式),從可執行程式解析符號給 DSO。為什麼?因為從可執行程式符號集「反向解析」DSO 符號與函式庫設計相違背(函式庫不知道使用它的程式),也沒有在所有平台下提供或標準化。實際上,可執行程式的全域符號通常不會重新匯出,因此無法在 DSO 中使用。找出一個強制連結器匯出所有全域符號的方法,是在執行階段使用 DSO 來延伸程式的過程中必須解決的主要問題。
共用函式庫方法是常見的方法,因為它是 DSO 機制所設計的內容,因此,它用於作業系統所提供的幾乎所有類型函式庫。
上述基於 DSO 的功能具有以下優點
LoadModule
httpd.conf
組態指令,而非在建置階段使用 configure
選項,在執行階段組裝。例如,這種方式可以單一 Apache httpd 安裝來執行不同的伺服器執行個體(標準和 SSL 版本,極簡和動態版本 [mod_perl、mod_php] 等)。apxs
組合,您可以在 Apache httpd 原始碼樹外部工作,且只需要 apxs -i
指令後接 apachectl restart
指令,就能將您當前開發模組的新版本載入正在執行的 Apache HTTP 伺服器。DSO 具有以下缺點
ld -lfoo
)(例如基於 a.out 的平台通常不提供這項功能,而基於 ELF 的平台則有提供),因此你無法對所有類型的模組使用 DSO 機制。換句話說,編譯為 DSO 檔案的模組僅限使用來自 Apache httpd 核心、C 程式庫 (libc
) 和 Apache httpd 核心所使用的所有其他動態或靜態函式庫或含有位置獨立程式碼的靜態函式庫檔案 (libfoo.a
) 中的符號。使用其他程式碼的唯一機會是確保 httpd 核心本身已包含對它的參照,或透過 dlopen()
自行載入程式碼。