?
This document uses PHP Chinese website manual Release
Apache HTTP服務(wù)器是一個(gè)模塊化的軟件,管理員可以通過(guò)選擇服務(wù)器中包含的模塊進(jìn)行功能增減。模塊可以在編譯時(shí)被靜態(tài)包含進(jìn)httpd
二進(jìn)制文件,也可以編譯成獨(dú)立于httpd
二進(jìn)制文件的動(dòng)態(tài)共享對(duì)象(DSO)。DSO模塊可以與服務(wù)器一起編譯,也可以用Apache擴(kuò)展工具(apxs
)單獨(dú)編譯。
本文闡述如何使用DSO模塊及其工作原理。
相關(guān)模塊 | 相關(guān)指令 |
---|---|
|
|
Apache對(duì)獨(dú)立模塊的DSO支持是建立在只能被靜態(tài)編譯進(jìn)Apache核心的mod_so
基礎(chǔ)之上的,這是core
以外唯一不能作為DSO存在的模塊,而其他所有已發(fā)布的Apache模塊,都可以通過(guò)安裝文檔中闡述中的編譯選項(xiàng)
--enable-module=shared
被獨(dú)立地編譯成DSO并使之生效。一個(gè)被編譯為mod_foo.so
的DSO模塊,可以在httpd.conf
中使用mod_so
的LoadModule
指令,在服務(wù)器啟動(dòng)或重新啟動(dòng)時(shí)被加載。
新提供的支持程序apxs
(APache
eXtenSion)可以在Apache源代碼樹(shù)之外編譯基于DSO的模塊,從而簡(jiǎn)化了Apache DSO模塊的建立過(guò)程。其原理很簡(jiǎn)單:安裝Apache時(shí),configure
的 make install
命令會(huì)安裝Apache C頭文件,并把依賴(lài)于特定平臺(tái)的編譯器和連接器參數(shù)傳給apxs
程序,使用戶可以脫離Apache的發(fā)布源代碼樹(shù)編譯其模塊源代碼,而不改變支持DSO的編譯器和連接器的參數(shù)。
Apache2.0 的DSO功能簡(jiǎn)要說(shuō)明:
mod_foo.c
為mod_foo.so
的DSO模塊:
$ ./configure --prefix=/path/to/install --enable-foo=shared
$ make install
mod_foo.c
為mod_foo.so
的DSO模塊:
$ ./configure --add-module=module_type:/path/to/3rdparty/mod_foo.c --enable-foo=shared
$ make install
$ ./configure --enable-so
$ make install
apxs
在Apache源碼樹(shù)以外編譯并安裝第三方模塊,比如編譯mod_foo.c
為mod_foo.so
的DSO模塊:
$ cd /path/to/3rdparty
$ apxs -c mod_foo.c
$ apxs -i -a -n foo mod_foo.la
共享模塊編譯完畢后,必須在httpd.conf
中用LoadModule
指令使Apache啟用該模塊。
現(xiàn)代的類(lèi)Unix系統(tǒng)都有一種叫動(dòng)態(tài)共享對(duì)象(DSO)的動(dòng)態(tài)連接/加載的巧妙的機(jī)制,從而可以在運(yùn)行時(shí)將編譯成特殊格式的代碼加載到一個(gè)可執(zhí)行程序的地址空間。
加載的方法通常有兩種:其一是在可執(zhí)行文件啟動(dòng)時(shí)由系統(tǒng)程序ld.so
自動(dòng)加載;其二是在可執(zhí)行程序中手動(dòng)地通過(guò)Unix加載器的系統(tǒng)接口執(zhí)行系統(tǒng)調(diào)用dlopen()/dlsym()
進(jìn)行加載。
按第一種方法,DSO通常被稱(chēng)為共享庫(kù)(shared libraries)或者DSO庫(kù)(DSO libraries),使用libfoo.so
或libfoo.so.1.2
的文件名,存儲(chǔ)在系統(tǒng)目錄中(通常是/usr/lib
),并在編譯安裝時(shí)使用連接器參數(shù) -lfoo
建立了指向可執(zhí)行程序的連接。通過(guò)設(shè)置連接器參數(shù) -R
或者環(huán)境變量LD_LIBRARY_PATH
,庫(kù)中硬編碼了可執(zhí)行文件的路徑,使Unix加載器能夠在可執(zhí)行程序啟動(dòng)時(shí)定位到位于/usr/lib
目錄中的libfoo.so
,以解析可執(zhí)行文件中尚未解析的位于DSO中的符號(hào)。
通常,DSO不會(huì)引用可執(zhí)行文件中的符號(hào)(因?yàn)樗峭ㄓ么a的可重用庫(kù)),也不會(huì)有后繼的解析動(dòng)作??蓤?zhí)行文件無(wú)須自己作任何動(dòng)作以使用DSO中的符號(hào),而完全由Unix加載器代辦(事實(shí)上,調(diào)用ld.so
的代碼是被連入每個(gè)可執(zhí)行文件的非靜態(tài)運(yùn)行時(shí)啟動(dòng)代碼的一部分)。動(dòng)態(tài)加載公共庫(kù)代碼的優(yōu)點(diǎn)是明顯的:只需要在系統(tǒng)庫(kù)libc.so
中存儲(chǔ)一次庫(kù)代碼,從而為每個(gè)程序節(jié)省了磁盤(pán)存儲(chǔ)空間。
按第二種方法,DSO通常被稱(chēng)為共享對(duì)象(shared
objects)或DSO文件(DSO files),可以使用任何文件名(但是規(guī)范的名稱(chēng)是foo.so
),被存儲(chǔ)在程序特定的目錄中,也不會(huì)自動(dòng)建立指向其所用的可執(zhí)行文件的連接,而由可執(zhí)行文件在運(yùn)行時(shí)自己調(diào)用dlopen()
來(lái)加載DSO到其地址空間,同時(shí)也不會(huì)進(jìn)行為可執(zhí)行文件解析DSO中符號(hào)的操作。Unix加載器會(huì)根據(jù)可執(zhí)行程序的輸出符號(hào)表和已經(jīng)加載的DSO庫(kù)自動(dòng)解析DSO中尚未解析的符號(hào)(尤其是無(wú)所不在的libc.so
中的符號(hào)),如此DSO就獲得了可執(zhí)行程序的符號(hào)信息,就好象是被靜態(tài)連接一樣。
最后,為了利用DSO API的優(yōu)點(diǎn),可執(zhí)行程序必須用dlsym()
解析DSO中的符號(hào),以備稍后在諸如指派表等等中使用。也就是說(shuō),可執(zhí)行程序必須自己解析其所需的符號(hào)。這種機(jī)制的優(yōu)點(diǎn)是允許不加載可選的程序部件,直到程序需要的時(shí)候才被動(dòng)態(tài)地加載(也就不需要內(nèi)存開(kāi)銷(xiāo)),以擴(kuò)展程序的功能。
雖然這種DSO機(jī)制看似很直接,但至少有一個(gè)難點(diǎn),就是在用DSO擴(kuò)展程序功能(第二種方法)時(shí)為DSO對(duì)可執(zhí)行程序中符號(hào)的進(jìn)行解析,這是因?yàn)椋?反向解析"可執(zhí)行程序中的DSO符號(hào)在所有標(biāo)準(zhǔn)平臺(tái)上與庫(kù)的設(shè)計(jì)都是矛盾的(庫(kù)不會(huì)知道什么程序會(huì)使用它)。實(shí)際應(yīng)用中,可執(zhí)行文件中的全局符號(hào)通常不是重輸出的,因此不能為DSO所用。所以在運(yùn)行時(shí)用DSO來(lái)擴(kuò)展程序功能,就必須找到強(qiáng)制連接器輸出所有全局符號(hào)的方法。
共享庫(kù)是一種典型的解決方法,因?yàn)樗螪SO機(jī)制,而且為操作系統(tǒng)所提供的幾乎所有類(lèi)型的庫(kù)所使用。另一方面,使用共享對(duì)象并不是許多程序?yàn)閿U(kuò)展其功能所采用的方法。
截止到1998年,只有少數(shù)的軟件包使用DSO機(jī)制在運(yùn)行時(shí)擴(kuò)展其功能,諸如 Perl 5(通過(guò)其XS機(jī)制和DynaLoader模塊),Netscape Server等。從1.3版本開(kāi)始,Apache也加入此列,因?yàn)锳pache已經(jīng)用了基于指派表(dispatch-list-based)的方法來(lái)連接外部模塊到Apache的核心。所以Apache也就當(dāng)然地在運(yùn)行時(shí)用DSO來(lái)加載其模塊。
上述基于DSO的功能有如下優(yōu)點(diǎn):
httpd.conf
中的配置命令LoadModule
來(lái)進(jìn)行,而不是在編譯中使用編譯選項(xiàng)
來(lái)進(jìn)行,因此顯得更靈活。比如,只需要安裝一個(gè)Apache,就可以運(yùn)行多個(gè)不同的服務(wù)器實(shí)例(如標(biāo)準(zhǔn)&SSL版本,濃縮&功能加強(qiáng)版本[mod_perl、PHP])。apxs
,可以脫離Apache源代碼樹(shù),僅需要一個(gè) apxs -i
和一個(gè) apachectl restart
命令,就可以把剛開(kāi)發(fā)的新模塊納入到運(yùn)行中的Apache服務(wù)器。DSO有如下缺點(diǎn):
ld -lfoo
),比如,基于a.out的平臺(tái)通常不提供此功能,而基于ELF的平臺(tái)則提供,因此DSO機(jī)制并不能被用于所有類(lèi)型的模塊?;蛘呖梢赃@樣說(shuō),編譯為DSO文件的模塊只能使用由Apache核心、C庫(kù)(libc
)和Apache核心所用的所有其他動(dòng)態(tài)或靜態(tài)的庫(kù)、含有獨(dú)立位置代碼的靜態(tài)庫(kù)(libfoo.a
)所提供的符號(hào)。而要使用其他代碼,就只能確保Apache核心本身包含對(duì)此代碼的引用,或者自己用dlopen()
來(lái)加載此代碼。