# 動態共享對象(DSO)支持
Apache HTTP服務器是一個模塊化的軟件,管理員可以通過選擇服務器中包含的模塊進行功能增減。模塊可以在編譯時被靜態包含進`httpd`二進制文件,也可以編譯成獨立于`httpd`二進制文件的動態共享對象(DSO)。DSO模塊可以與服務器一起編譯,也可以用Apache擴展工具(`apxs`)單獨編譯。
本文闡述如何使用DSO模塊及其工作原理。
## 實現
相關模塊
* `mod_so`
相關指令
* `LoadModule`
Apache對獨立模塊的DSO支持是建立在只能被靜態編譯進Apache核心的`mod_so`基礎之上的,這是`core`以外唯一不能作為DSO存在的模塊,而其他所有已發布的Apache模塊,都可以通過[安裝文檔](#calibre_link-249)中闡述中的`編譯選項` `--enable-_module_=shared` 被獨立地編譯成DSO并使之生效。一個被編譯為`mod_foo.so`的DSO模塊,可以在`httpd.conf`中使用`mod_so`的`LoadModule`指令,在服務器啟動或重新啟動時被加載。
新提供的支持程序`apxs`(<dfn class="calibre27">APache eXtenSion</dfn>)可以在Apache源代碼樹_之外_編譯基于DSO的模塊,從而簡化了Apache DSO模塊的建立過程。其原理很簡單:安裝Apache時,`configure`的 `make install` 命令會安裝Apache C頭文件,并把依賴于特定平臺的編譯器和連接器參數傳給`apxs`程序,使用戶可以脫離Apache的發布源代碼樹編譯其模塊源代碼,而不改變支持DSO的編譯器和連接器的參數。
## 用法概要
Apache2.0 的DSO功能簡要說明:
1. 編譯并安裝_已發布_的Apache模塊,比如編譯`mod_foo.c`為`mod_foo.so`的DSO模塊:
```
$ ./configure --prefix=/path/to/install --enable-foo=shared
$ make install
```
2. 編譯并安裝_第三方_模塊,比如編譯`mod_foo.c`為`mod_foo.so`的DSO模塊:
```
$ ./configure --add-module=module_type:/path/to/3rdparty/mod_foo.c --enable-foo=shared
$ make install
```
3. 配置Apache以便_以后安裝_共享模塊:
```
$ ./configure --enable-so
$ make install
```
4. 用`apxs`在Apache源碼樹_以外_編譯并安裝_第三方_模塊,比如編譯`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啟用該模塊。
## 背景知識
現代的類Unix系統都有一種叫_動態共享對象_(DSO)的動態連接/加載的巧妙的機制,從而可以在運行時將編譯成特殊格式的代碼加載到一個可執行程序的地址空間。
加載的方法通常有兩種:其一是在可執行文件啟動時由系統程序`ld.so`自動加載;其二是在可執行程序中手動地通過Unix加載器的系統接口執行系統調用`dlopen()/dlsym()`進行加載。
按第一種方法,DSO通常被稱為_共享庫_(shared libraries)或者_DSO庫_(DSO libraries),使用`libfoo.so`或`libfoo.so.1.2`的文件名,存儲在系統目錄中(通常是`/usr/lib`),并在編譯安裝時使用連接器參數 `-lfoo` 建立了指向可執行程序的連接。通過設置連接器參數 `-R` 或者環境變量`LD_LIBRARY_PATH` ,庫中硬編碼了可執行文件的路徑,使Unix加載器能夠在可執行程序啟動時定位到位于`/usr/lib`目錄中的`libfoo.so` ,以解析可執行文件中尚未解析的位于DSO中的符號。
通常,DSO不會引用可執行文件中的符號(因為它是通用代碼的可重用庫),也不會有后繼的解析動作。可執行文件無須自己作任何動作以使用DSO中的符號,而完全由Unix加載器代辦(事實上,調用`ld.so`的代碼是被連入每個可執行文件的非靜態運行時啟動代碼的一部分)。動態加載公共庫代碼的優點是明顯的:只需要在系統庫`libc.so`中存儲一次庫代碼,從而為每個程序節省了磁盤存儲空間。
按第二種方法,DSO通常被稱為_共享對象_(shared objects)或_DSO文件_(DSO files),可以使用任何文件名(但是規范的名稱是`foo.so`),被存儲在程序特定的目錄中,也不會自動建立指向其所用的可執行文件的連接,而由可執行文件在運行時自己調用`dlopen()`來加載DSO到其地址空間,同時也不會進行為可執行文件解析DSO中符號的操作。Unix加載器會根據可執行程序的輸出符號表和已經加載的DSO庫自動解析DSO中尚未解析的符號(尤其是無所不在的`libc.so`中的符號),如此DSO就獲得了可執行程序的符號信息,就好象是被靜態連接一樣。
最后,為了利用DSO API的優點,可執行程序必須用`dlsym()`解析DSO中的符號,以備稍后在諸如指派表_等等_中使用。也就是說,可執行程序必須自己解析其所需的符號。這種機制的優點是允許不加載可選的程序部件,直到程序需要的時候才被動態地加載(也就不需要內存開銷),以擴展程序的功能。
雖然這種DSO機制看似很直接,但至少有一個難點,就是在用DSO擴展程序功能(第二種方法)時為DSO對可執行程序中符號的進行解析,這是因為,"反向解析"可執行程序中的DSO符號在所有標準平臺上與庫的設計都是矛盾的(庫不會知道什么程序會使用它)。實際應用中,可執行文件中的全局符號通常不是重輸出的,因此不能為DSO所用。所以在運行時用DSO來擴展程序功能,就必須找到強制連接器輸出所有全局符號的方法。
共享庫是一種典型的解決方法,因為它符合DSO機制,而且為操作系統所提供的幾乎所有類型的庫所使用。另一方面,使用共享對象并不是許多程序為擴展其功能所采用的方法。
截止到1998年,只有少數的軟件包使用DSO機制在運行時擴展其功能,諸如 Perl 5(通過其XS機制和DynaLoader模塊),Netscape Server等。從1.3版本開始,Apache也加入此列,因為Apache已經用了基于指派表(dispatch-list-based)的方法來連接外部模塊到Apache的核心。所以Apache也就當然地在運行時用DSO來加載其模塊。
## 優點和缺點
上述基于DSO的功能有如下優點:
* 由于服務器包的裝配工作可以在運行時使用`httpd.conf`中的配置命令`LoadModule`來進行,而不是在編譯中使用`編譯選項`來進行,因此顯得更靈活。比如,只需要安裝一個Apache,就可以運行多個不同的服務器實例(如標準&SSL版本,濃縮&功能加強版本[mod_perl、PHP])。
* 服務器可以在安裝后使用第三方模塊被輕易地擴展。這至少對廠商發行包的維護者有巨大的好處,他可以建立一個Apache核心包,而為諸如PHP、mod_perl、mod_fastcgi等擴展另建附加的包。
* 更簡單的Apache模塊原型。使用DSO配合`apxs`,可以脫離Apache源代碼樹,僅需要一個 `apxs -i` 和一個 `apachectl restart` 命令,就可以把剛開發的新模塊納入到運行中的Apache服務器。
DSO有如下缺點:
* 由于并不是所有操作系統都支持動態加載代碼到一個程序的地址空間,因此DSO機制并不能用于所有平臺。
* 由于Unix加載器必須進行符號解析,服務器的啟動會慢20%左右。
* 在某些平臺上,位置獨立代碼(positon independent code[PIC])需要復雜的匯編語言技巧來實現相對尋址,而絕對尋址則不需要,因此服務器在運行時會慢5%左右。
* 由于DSO模塊不能在所有平臺上被其他基于DSO的庫所連接(`ld -lfoo`),比如,基于a.out的平臺通常不提供此功能,而基于ELF的平臺則提供,因此DSO機制并不能被用于所有類型的模塊。或者可以這樣說,編譯為DSO文件的模塊只能使用由Apache核心、C庫(`libc`)和Apache核心所用的所有其他動態或靜態的庫、含有獨立位置代碼的靜態庫(`libfoo.a`)所提供的符號。而要使用其他代碼,就只能確保Apache核心本身包含對此代碼的引用,或者自己用`dlopen()`來加載此代碼。
- Apache HTTP Server Version 2.2 文檔 [最后更新:2006年3月21日]
- 版本說明
- 從1.3升級到2.0
- 從2.0升級到2.2
- Apache 2.2 新特性概述
- Apache 2.0 新特性概述
- The Apache License, Version 2.0
- 參考手冊
- 編譯與安裝
- 啟動Apache
- 停止和重啟
- 配置文件
- 配置段(容器)
- 緩沖指南
- 服務器全局配置
- 日志文件
- 從URL到文件系統的映射
- 安全方面的提示
- 動態共享對象(DSO)支持
- 內容協商
- 自定義錯誤響應
- 地址和端口的綁定(Binding)
- 多路處理模塊
- Apache的環境變量
- Apache處理器的使用
- 過濾器(Filter)
- suEXEC支持
- 性能方面的提示
- URL重寫指南
- Apache虛擬主機文檔
- 基于主機名的虛擬主機
- 基于IP地址的虛擬主機
- 大批量虛擬主機的動態配置
- 虛擬主機示例
- 深入研究虛擬主機的匹配
- 文件描述符限制
- 關于DNS和Apache
- 常見問題
- 經常問到的問題
- Apache的SSL/TLS加密
- SSL/TLS高強度加密:緒論
- SSL/TLS高強度加密:兼容性
- SSL/TLS高強度加密:如何...?
- SSL/TLS Strong Encryption: FAQ
- 如何.../指南
- 認證、授權、訪問控制
- CGI動態頁面
- 服務器端包含入門
- .htaccess文件
- 用戶網站目錄
- 針對特定平臺的說明
- 在Microsoft Windows中使用Apache
- 在Microsoft Windows上編譯Apache
- Using Apache With Novell NetWare
- Running a High-Performance Web Server on HPUX
- The Apache EBCDIC Port
- 服務器和支持程序
- httpd - Apache超文本傳輸協議服務器
- ab - Apache HTTP服務器性能測試工具
- apachectl - Apache HTTP服務器控制接口
- apxs - Apache 擴展工具
- configure - 配置源代碼樹
- dbmmanage - 管理DBM格式的用戶認證文件
- htcacheclean - 清理磁盤緩沖區
- htdbm - 操作DBM密碼數據庫
- htdigest - 管理用于摘要認證的用戶文件
- httxt2dbm - 生成RewriteMap指令使用的dbm文件
- htpasswd - 管理用于基本認證的用戶文件
- logresolve - 解析Apache日志中的IP地址為主機名
- rotatelogs - 滾動Apache日志的管道日志程序
- suexec - 在執行外部程序之前切換用戶
- 其他程序
- 雜項文檔
- 與Apache相關的標準
- Apache模塊
- 描述模塊的術語
- 描述指令的術語
- Apache核心(Core)特性
- Apache MPM 公共指令
- Apache MPM beos
- Apache MPM event
- Apache MPM netware
- Apache MPM os2
- Apache MPM prefork
- Apache MPM winnt
- Apache MPM worker
- Apache模塊 mod_actions
- Apache模塊 mod_alias
- Apache模塊 mod_asis
- Apache模塊 mod_auth_basic
- Apache模塊 mod_auth_digest
- Apache模塊 mod_authn_alias
- Apache模塊 mod_authn_anon
- Apache模塊 mod_authn_dbd
- Apache模塊 mod_authn_dbm
- Apache模塊 mod_authn_default
- Apache模塊 mod_authn_file
- Apache模塊 mod_authnz_ldap
- Apache模塊 mod_authz_dbm
- Apache模塊 mod_authz_default
- Apache模塊 mod_authz_groupfile
- Apache模塊 mod_authz_host
- Apache模塊 mod_authz_owner
- Apache模塊 mod_authz_user
- Apache模塊 mod_autoindex
- Apache模塊 mod_cache
- Apache模塊 mod_cern_meta
- Apache模塊 mod_cgi
- Apache模塊 mod_cgid
- Apache模塊 mod_charset_lite
- Apache模塊 mod_dav
- Apache模塊 mod_dav_fs
- Apache模塊 mod_dav_lock
- Apache模塊 mod_dbd
- Apache模塊 mod_deflate
- Apache模塊 mod_dir
- Apache模塊 mod_disk_cache
- Apache模塊 mod_dumpio
- Apache模塊 mod_echo
- Apache模塊 mod_env
- Apache模塊 mod_example
- Apache模塊 mod_expires
- Apache模塊 mod_ext_filter
- Apache模塊 mod_file_cache
- Apache模塊 mod_filter
- Apache模塊 mod_headers
- Apache模塊 mod_ident
- Apache模塊 mod_imagemap
- Apache模塊 mod_include
- Apache模塊 mod_info
- Apache模塊 mod_isapi
- Apache模塊 mod_ldap
- Apache模塊 mod_log_config
- Apache模塊 mod_log_forensic
- Apache模塊 mod_logio
- Apache模塊 mod_mem_cache
- Apache模塊 mod_mime
- Apache模塊 mod_mime_magic
- Apache模塊 mod_negotiation
- Apache模塊 mod_nw_ssl
- Apache模塊 mod_proxy
- Apache模塊 mod_proxy_ajp
- Apache模塊 mod_proxy_balancer
- Apache模塊 mod_proxy_connect
- Apache模塊 mod_proxy_ftp
- Apache模塊 mod_proxy_http
- Apache模塊 mod_rewrite
- Apache模塊 mod_setenvif
- Apache模塊 mod_so
- Apache模塊 mod_speling
- Apache模塊 mod_ssl
- Apache模塊 mod_status
- Apache模塊 mod_suexec
- Apache模塊 mod_unique_id
- Apache模塊 mod_userdir
- Apache模塊 mod_usertrack
- Apache模塊 mod_version
- Apache模塊 mod_vhost_alias
- Developer Documentation for Apache 2.0
- Apache 1.3 API notes
- Debugging Memory Allocation in APR
- Documenting Apache 2.0
- Apache 2.0 Hook Functions
- Converting Modules from Apache 1.3 to Apache 2.0
- Request Processing in Apache 2.0
- How filters work in Apache 2.0
- Apache 2.0 Thread Safety Issues
- 詞匯和索引
- 詞匯表
- 指令索引
- 指令速查
- 模塊索引
- 站點導航