在 SBCL 等开源 Lisp 平台上运行 CL-HTTP (part 1)

在 SBCL 等开源 Lisp 平台上运行 CL-HTTP (part 1)_第1张图片

现在我来说明在 4 种开源 Common Lisp 平台上运行  CL-HTTP 的方法,四种平台分别是  SBCL、 Clozure CL、 CMUCL 和  Macintosh Common Lisp (MCL)。 我相信我所提供的这些信息对某些 Common Lisp 爱好者来说将是梦寐以求的。

背景

过去我也曾在博客里多次提到 CL-HTTP,多年来也一直在实际地学习和使用这个软件。概括地说,CL-HTTP 是一个纯 Common Lisp 实现的高级 Web 应用服务器。和 Common Lisp 社区的其他流行 HTTP 服务器,例如  Hunchentoot 和  AllegroServe 相比,CL-HTTP 不仅提供了 HTTP 1.1 协议的完整实现,还提供了一体化的解决方案,包括基于 Lisp 宏的动态 HTML/XHTML 代码生成,面向对象的 Web 交互设计,权限控制,HTTPS 和 HTTP Proxy 支持(带有缓存)等,另外它还提供 HTTP 客户端,SMTP/POP3/FTP 支持以及其他数不清的高级特性。 CL-HTTP 是目前开源 Common Lisp 项目中规模最大、最复杂的,其核心 server 模块源代码 5 万多行,所有模块连同各种平台的移植在内共计 35 万行 Common Lisp 代码(bz2 压缩一下其实只有不到 7M),可谓是浩如烟海,Lisp 新手往往迷失在其庞大的目录树里。

CL-HTTP 最初是在 Symbolics Lisp Machine 上开发的,1994 年开始公开了源代码。作者是 MIT AI 实验室 ( CSAIL) 的教授  John C. Malley,目前主要维护者还包括  Rainer Joswig 和来自几个商业 CL 平台的专家,尤其是 LispWorks 公司的 Martin Simmons。CL-HTTP 的开发工作非常缓慢,但也极度稳定可靠,不过主要是在上一代的很多商业平台上。CL-HTTP 的源代码 SVN 是不公开的,仅少量核心开发者具有访问权限,但是一般可以通过发信给邮件列表向开发者索取最新的源代码。这给追踪其源代码变化带来了一定困难,因此我自己维护了一个私有的 SVN 库将历史上获得的所有代码快照全部提交在里面,再注入我自己的一些补丁。

获得最新的 CL-HTTP 源码

CL-HTTP 网站上目前 公开下载的最后版本 70.190a 已经是很老的版本了,目前的最新版本是 70.218,SVN revision 至少为 436。Rainer Joswig 定期将 SVN 上的最新版本打包放在它的个人主页上,下载地址是:

http://lispm.dyndns.org/distributions/

其中目前的最新版本的下载文件名是 cl-http-70-218-s436.tar.gz。不过由于上游合并补丁的速度非常慢,即便是这个最新版本仍然有一些问题导致 SBCL 下无法顺利加载。推荐使用的是本文附件中的版本,它来自我自行维护的 CL-HTTP 私有 SVN 库,修复了很多 bug,补丁已提交到上游但尚未被合并。有兴趣的读者可以同时下载两个文件然后自行比对其中的差异。 

源代码结构

CL-HTTP 的源代码可以大致分为下列 7 个部分:
  1. 平台无关的核心代码,包括 HTTP/HTTPS 协议本身的实现和 HTML、URL 等标准的实现代码;
  2. 平台无关的周边代码,包括 HTML 解析器、客户端、SMTP/FTP 等协议的实现等;
  3. 平台无关的用户贡献代码,包括 POP3 客户端、XML 工具箱以及最重要的可移植模板 (port-template) 代码等;
  4. 平台相关的核心代码,包括适用于 CMUCL、LispWorks、MCL、SCL 等主要平台的网络和工具性代码等;
  5. 平台相关的周边代码,例如 LispWorks 和 MCL 下的图形界面控制台等;
  6. 平台相关的用户贡献代码,例如 LispWorks 下的 UTF-8 支持、远程 Listener 和数据库认证接口等;
  7. 示例站点的源代码和静态文件。

以下简要介绍 CL-HTTP 的源代码目录结构,最顶层各目录的说明如下表所示:

目录名 类别 用途说明
 acl  平台相关代码  Allegro CL 移植
 client  平台无关的周边代码  HTTP 客户端
 clim  平台无关的周边代码  基于 CLIM 的图形控制台
 cmucl  平台相关代码  CMU Common Lisp 移植
 contrib  平台无关的用户贡献代码  各种有用的扩展,尤其包括可移植模板 (port-template)
 examples  示例站点  示例站点的源代码
 ftp  平台无关的周边代码  FTP 客户端(代理)
 html-parser  平台无关的周边代码  HTML 解析器
 lambda-ir  平台无关的周边代码  全文索引
 lcl  平台相关代码  Lucid/Liquid Common Lisp 移植
 lispm  平台相关代码  最初在 Symbolics Lisp Machine 上开发的全部代码
 lw  平台相关代码  LispWorks 移植
 mcl  平台相关代码  Macintosh Common Lisp 移植
 proxy  平台无关的核心代码  HTTP Proxy(正反向都有)
 scl  平台相关代码  Scieneer Common Lisp 移植
 server  平台无关的核心代码  核心 HTTP 协议实现和 HTML 生成代码等
 smtp  平台无关的周边代码  SMTP 协议实现
 standards  静态文件  相关 RFC 标准的文本,通过示例站点可访问到
 w3p  平台无关的周边代码  W3P (Presentation-based Interface)
 w4  平台无关的周边代码  W4 Constraint-Guided Web Walker
 www  示例站点  示例站点的静态页面和其他数据文件

在 SBCL 上启动 CL-HTTP 的方法

正确在 SBCL 上启动 CL-HTTP 的先决条件是必须拥有一个支持多线程 (sb-thread) 的 SBCL,其次一定要使用比较新的版本(目前最后发布的 1.0.49 经测试是可用的)。遗憾的是,目前 SBCL 官方站点提供的二进制版本只在 Linux/x86 和 Linux/AMD64 上默认打开了多线程支持,其他平台要么不支持多线程,要么就是默认关闭的。SBCL 目前官方的 Windows 版本多线程支持不好,推荐改用 Anton Kovalenko 维护的  sbcl-win32-threads 分支,遗憾的是,我一时找不到预编译版本的下载地址了。Mac OS X 用户需要先安装官方的二进制版本,然后使用 SBCL 源代码重新编译支持多线程的版本。这需要在源代码顶层目录里放置一个名为 customize-target-features.lisp 的文件,内容如下所示:

(lambda (features)
  (flet ((enable (x)
           (pushnew x features))
         (disable (x)
           (setf features (remove x features))))
    (enable :sb-thread)))

具体的编译和安装方法可参见 SBCL 源代码目录里的 INSTALL 文件。以下假设一个支持多线程的 SBCL 已顺利安装。

在 SBCL 下编译 CL-HTTP 最重要的一环是加载启动文件,它的相对路径是 contrib/kpoeck/port-template/load.lisp。

首先进入 CL-HTTP 源代码根目录,然后启动一个 SBCL 环境并加载上述文件:

binghe@binghe-mac:~/Lisp/self/cl-http$ sbcl
This is SBCL 1.0.49, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
* (load "contrib/kpoeck/port-template/load.lisp")

; loading #P"/Users/binghe/Lisp/self/cl-http/contrib/kpoeck/port-template/load.lisp"
;; loading #P"/Users/binghe/lib/sbcl/sb-introspect/sb-introspect.asd"
;; loading #P"/Users/binghe/lib/sbcl/sb-introspect/introspect.fasl"
;; loading #P"/Users/binghe/Lisp/self/cl-http/contrib/kpoeck/port-template/translations.lisp"

; file: /Users/binghe/Lisp/self/cl-http/contrib/kpoeck/port-template/load.lisp
; in: DEFUN LOAD-THE-THING
;     (POTENTIALLY-COMPILE-FILE VALUE)
; caught STYLE-WARNING:
;   undefined function: POTENTIALLY-COMPILE-FILE
; compilation unit finished
;   Undefined function:
;     POTENTIALLY-COMPILE-FILE
;   caught 1 STYLE-WARNING condition

; in: DEFUN LOAD-CL-HTTP-FILES
;     (LOAD-CL-HTTP-FILES-INTERNAL *FILES-CL-HTTP*)
; caught STYLE-WARNING:
;   undefined function: LOAD-CL-HTTP-FILES-INTERNAL
; compilation unit finished
;   Undefined function:
;     LOAD-CL-HTTP-FILES-INTERNAL
;   caught 1 STYLE-WARNING condition

Excecute (COMPILE-ALL) to compile the system. 

Excecute (LOAD-CL-HTTP-TESTER) to test the system without sockets. 

To start the simple-server do (http::start-examples) .
T

忽略那些警告,注意结尾处的三句话:执行 (COMPILE-ALL) 可以编译整个系统,执行 (LOAD-CL-HTTP-TESTER) 可以在不使用网络的情况下测试整个系统;使用 (HTTP::START-EXAMPLES) 启动示例站点。

正确的启动方法是,首先执行  (COMPILE-ALL) 然后 跳过测试,直接使用 (HTTP::START-EXAMPLES) 来启动示例站点。一次完全编译可能需要花几分钟时间,并且每次只能做完全编译(以后会说明怎样节省时间)。启动成功后有类似下面的提示:

[2011-06-30 23:42:32]  HTTP Proxy Service Enabled on port 8000 for NIL.
[2011-06-30 23:42:32]  HTTP service enabled for: http://localhost:8000/

如果顺利走到这一步了,那么恭喜你,可以打开浏览器访问  http://localhost:8000/,然后就可以看到本文插图中的示例站点 Web 页面了。

(后记:附件的源代码有所更新,修复了一个 port-template 下的小问题,请看到的读者下载新版本 (r75))

新的下载地址:
cl-http-70-218-s436-binghe-r75-fixed-v.part1.rar
cl-http-70-218-s436-binghe-r75-fixed-v.part2.rar

or  files.me.com/binghe.lisp/aw4rfb

(未完待续)

你可能感兴趣的:(开源,lisp,sbcl)