<-
Apache > HTTP Server > 文档 > 版本 2.4

动态共享对象 (DSO) 支持

可用语言:  en  |  fr  |  ja  |  ko  |  tr 

Apache HTTP Server 是一个模块化程序,管理员可以通过选择一组模块来决定在服务器中包含哪些功能。模块将被编译为动态共享对象 (DSO),它们独立于主 httpd 二进制文件存在。DSO 模块可以在服务器构建时编译,也可以在稍后使用 Apache 扩展工具 (apxs) 编译并添加。

或者,模块可以在服务器构建时静态编译到 httpd 二进制文件中。

本文档介绍了如何使用 DSO 模块以及它们背后的理论。

Support Apache!

另请参阅

top

实现

加载单个 Apache httpd 模块的 DSO 支持基于名为 mod_so 的模块,该模块必须静态编译到 Apache httpd 核心。除了 core 之外,它是唯一不能放入 DSO 本身的模块。实际上,所有其他分发的 Apache httpd 模块都将被放置到 DSO 中。在将模块编译到名为 mod_foo.so 的 DSO 后,您可以在 httpd.conf 文件中使用 mod_soLoadModule 指令在服务器启动或重启时加载此模块。

可以通过 configure--enable-mods-static 选项禁用单个模块的 DSO 构建,如 安装文档 中所述。

为了简化 Apache httpd 模块的 DSO 文件创建(尤其是第三方模块),提供了一个名为 apxs (APache eXtenSion) 的支持程序。它可用于在 Apache httpd 源代码树之外构建基于 DSO 的模块。这个想法很简单:在安装 Apache HTTP Server 时,configuremake install 过程会安装 Apache httpd C 头文件,并将用于构建 DSO 文件的平台相关编译器和链接器标志放入 apxs 程序中。这样,用户就可以使用 apxs 编译他的 Apache httpd 模块源代码,而无需 Apache httpd 分发源代码树,也无需为 DSO 支持调整平台相关的编译器和链接器标志。

top

使用摘要

为了让您了解 Apache HTTP Server 2.x 的 DSO 功能,这里有一个简短而简洁的摘要

  1. 构建并安装一个分发的 Apache httpd 模块,例如 mod_foo.c,到它自己的 DSO mod_foo.so

    $ ./configure --prefix=/path/to/install --enable-foo
    $ make install

  2. 使用所有模块启用 Apache HTTP Server。服务器启动时只会加载基本集。您可以通过激活或停用 httpd.conf 中的 LoadModule 指令来更改加载的模块集。

    $ ./configure --enable-mods-shared=all
    $ make install

  3. 某些模块仅对开发人员有用,在使用模块集all时不会构建。要构建所有可用的模块,包括开发人员模块,请使用reallyall。此外,可以通过配置选项 --enable-load-all-modules 激活所有构建模块的 LoadModule 指令。

    $ ./configure --enable-mods-shared=reallyall --enable-load-all-modules
    $ make install

  4. 使用 apxs 在 Apache httpd 源代码树之外构建并安装一个第三方 Apache httpd 模块,例如 mod_foo.c,到它自己的 DSO mod_foo.so

    $ cd /path/to/3rdparty
    $ apxs -cia mod_foo.c

在所有情况下,一旦共享模块编译完成,您必须在 httpd.conf 中使用 LoadModule 指令告诉 Apache httpd 激活该模块。

有关更多详细信息,请参阅 apxs 文档

top

背景

在现代 Unix 派生系统中,存在一种称为动态共享对象 (DSO) 的动态链接/加载机制,它提供了一种方法来构建特殊格式的程序代码片段,以便在运行时将其加载到可执行程序的地址空间中。

这种加载通常可以通过两种方式完成:由名为 ld.so 的系统程序在可执行程序启动时自动完成,或者通过系统调用 dlopen()/dlsym() 手动从正在执行的程序中通过对 Unix 加载程序的编程系统接口完成。

在第一种方式中,DSO 通常被称为共享库DSO 库,并命名为 libfoo.solibfoo.so.1.2。它们驻留在系统目录(通常为 /usr/lib)中,并且通过在链接器命令中指定 -lfoo 来建立与可执行程序的链接。这将库引用硬编码到可执行程序文件中,以便在启动时,Unix 加载程序能够在 /usr/lib 中找到 libfoo.so,在通过链接器选项(如 -R)硬编码的路径中找到,或在通过环境变量 LD_LIBRARY_PATH 配置的路径中找到。然后,它会解析可执行程序中所有(尚未解析的)符号,这些符号在 DSO 中可用。

可执行程序中的符号通常不会被 DSO 引用(因为它是一个通用的代码库),因此无需进行进一步的解析。可执行程序无需自行执行任何操作即可使用 DSO 中的符号,因为所有解析都由 Unix 加载程序完成。(实际上,调用 ld.so 的代码是运行时启动代码的一部分,该代码链接到每个已非静态绑定到可执行程序中。)动态加载通用库代码的优势显而易见:库代码只需要存储一次,在一个系统库中,例如 libc.so,为每个程序节省磁盘空间。

在第二种方式中,DSO 通常被称为共享对象DSO 文件,并且可以使用任意扩展名命名(尽管规范名称为 foo.so)。这些文件通常保留在程序特定的目录中,并且没有与使用它们的执行程序建立自动链接。相反,可执行程序在运行时通过 dlopen() 手动将 DSO 加载到其地址空间中。此时,不会对可执行程序解析 DSO 中的任何符号。但相反,Unix 加载程序会自动解析 DSO 中所有(尚未解析的)符号,这些符号来自可执行程序及其已加载的 DSO 库(尤其是来自无处不在的 libc.so 的所有符号)导出的符号集。这样,DSO 就可以了解可执行程序的符号集,就好像它最初是与可执行程序静态链接的一样。

最后,为了利用 DSO 的 API,可执行程序必须通过 dlsym() 解析 DSO 中的特定符号,以便在以后的调度表中使用。换句话说:可执行程序必须手动解析它需要使用的每个符号。这种机制的优势在于,可选的程序部分无需加载(因此不会占用内存),直到它们被相关程序需要。需要时,这些程序部分可以动态加载以扩展基本程序的功能。

虽然这种 DSO 机制听起来很简单,但至少有一个困难的步骤:在使用 DSO 扩展程序时,从可执行程序解析 DSO 符号以供 DSO 使用(第二种方式)。为什么?因为“反向解析”可执行程序符号集中的 DSO 符号违反了库设计(库不知道它被哪些程序使用),并且并非所有平台都提供此功能,也未标准化。实际上,可执行程序的全局符号通常不会重新导出,因此无法在 DSO 中使用。找到一种方法来强制链接器导出所有全局符号是使用 DSO 在运行时扩展程序时必须解决的主要问题。

共享库方法是典型的,因为它正是 DSO 机制的设计目的,因此它用于操作系统提供的几乎所有类型的库。

top

优点和缺点

上述基于 DSO 的功能具有以下优点

DSO 具有以下缺点

可用语言:  en  |  fr  |  ja  |  ko  |  tr 

top

评论

注意
这不是一个问答区。此处发布的评论应针对改进文档或服务器的建议,如果评论已被实施或被认为无效/偏离主题,则可能会被我们的版主删除。有关如何管理 Apache HTTP Server 的问题,请咨询我们的 IRC 频道 #httpd(位于 Libera.chat)或发送至我们的 邮件列表