恩,打算写个连载

这个东东首发在水木社区的 TeX 版,反响还不错,就贴来大家一同讨论吧 🙂

谈谈 TeX 系统的构建过程,不过这个其实挺没意思的,如果只是用 TeX,而不打算修改 TeX 的代码的人完全不需要了解这个,我也不会涉及什么 TeXBook 里的内容,不知道有人有兴趣不?先贴一小段,要是大家有兴趣我就继续贴。呵呵,也算是一个开发了几十年的软件如何演化的一点掌故。

偶尔,你可能会突发奇想:平时自己用的这些 tex, latex, pdftex 是怎么来的?——是怎么写出来的,又是怎么编译出来的?

愿意究根问底的话,可以先自己动手试一试,目前可以工作的最小的 TeX 系统是 web2c,我们常用的发行版中的二进制程序,都是根据 web2c 中提供的代码,基本不作修改,或者只作很小修改编译而来的,所以,你可以先从 http://www.tug.org/ftp/tex/web2c.tar.gz 下载一份 web2c 的代码,解压开来,听我一步步的讲。

众所周知,Knuth 最早是在一台 DEC PDP-11 上用一种叫做 SAIL 的语言编写的 TeX,尔后他和一些合作者,开始在 Stanford 大学实验一种叫做 literate programming (文学编程) 的新式编程方法,他们设计了一套叫做 WEB 的系统,用 Pascal 语言来编写程序,用 TeX 来编写文档,将两者交织为一张“网”。

经过几年的不断修改,WEB 系统和 TeX 系统相互的影响下逐渐成熟,到 1982 年的时候,两者都基本上稳定下来,此时的 TeX 系统,核心就是一个 tex.web 文件。OK, 看看你刚刚解压出来的 web2c 目录下是不是有这么一个文件?那就是 Knuth 亲手写的,原封不动。

WEB 系统中有两个独立运行的程序,一个叫做 tangle (扰乱?) 一个叫 weave (编织?),运行 tangle tex.web 将生成一个叫做 tex.p 的 Pascal 程序,这个程序可以用任何现代的 Pascal 编译器编译;而运行 weave tex.web 将生成 tex.tex,你可以用自己系统里已经安装的 tex 来 tex tex.tex 得到这个程序的文档:tex.dvi。

我相信很多人看到这里就会觉得相当无聊,那不妨认为你现在用的 TeX 系统就是这么来的句号。如果你坚持到现在还在继续看,那就可以接下去看更完整一点的故事。

Knuth 当时写着写着,居然写了一个三万多行代码的文件出来 (灌水王啊~) 这已经很恐怖了,可是后来大家要接着在他后边修改就很累了,他自己也得做 bug fix 不是?所以就给 WEB 系统添加了一个功能:合并主程序和 change file 的功能。

其实这个 change file,和我们现在常用的 diff 出来的 patch 结构也差不多,无非是原来代码的上下文,和要修改成的代码。比如在 tex.ch 里,你可以看到:

@x
原代码
@y
新代码
@z

这就是一个完整的修改单元。tangle 和 weave 都同时接受主程序和 change file 两个参数,将两者归并起来再行生成 Pascal 程序和 tex 文档,也就是说,实际的编译过程是这样的:

tangle tex.web tex.ch 得到 tex.p
weave tex.web tex.ch 得到 tex.tex

可是后来,Knuth 又说,TeX 这个程序应该 freeze 下来,大家不要再改了啊,想改,就换个名字,不要再叫做 tex 了。所以后来陆陆续续就出现 etex, omega, pdftex 等等增强版本,可是大家做这些增强版本的时候,也不好意思直接在 Knuth 的代码上改啊 (恩,大牛写的代码只能拜),就纷纷创建自己的 change file。渐渐的 change file 就多了起来,比如 XeTeX, 要归并的 change file 有四五个之多,可是 tangle 和 weave 都只支持一个 change file 啊,于是就有人写了一个叫做 tie 的程序,专门做这种归并工作 (和 Larry Wall 写的 patch 一样),你可以指定一个主文件和 9 个以内的 change file,按顺序一个一个归并起来。

所以我们看 etex 的编译过程 (在 etexdir/etex.mk 这个 Makefile 里可以看到),就是先:

tie -m etex.web tex.web etex.ch etex.fix

得到 etex.web,然后 tangle etex.web 得到 etex.p 的。

可是 Knuth 开发 TeX 的那个时代 C 还没有获得大众 (OK,如果计算机科学家也算作大众的话) 的欢迎,也许因为 Knuth 本人和 Nicklaus Wirth 关系也比较铁,WEB 就优先选用了 Pascal 语言来编写 TeX,然而到了 90 年代,Pascal 渐渐退出了大家的视野,尤其在 Unix 系统下,C 更是金科玉律一般没有任何其他语言能替代,考虑到普及的原因,也考虑到方便与其他 C 语言编写的模块一同链接的原因,一班人开始考虑把 TeX 的代码转换为 C 的可能性,这就产生了 web2c。(web2c 一位长期的维护者 Karl Berry 就是现任 TUG 主席,也是 TeXLive 的主要维护者之一。)

最直接的办法就是把 tangle 后的 Pascal 代码转换为 C 代码,web2c 也正是如此设计的,毕竟 Knuth 当时为了保证尽可能的方便移植,几乎没有用到只有 Pascal 语言才有的特性,所涵盖的功能现代的 C 编译器 都已具备。所以他们采取的方法就是用 lex 和 yacc 写出了一个把 tangle 输出转换为 C 代码的程序。

那么,究竟应该如何调用 web2c 来生成 C 代码呢?生成出来的代码又该如何编译呢?且听下回分解。

Author: jjgod

A software engineer from China, working on text rendering for a fruit company. Interested in typography and science fiction.

10 thoughts on “恩,打算写个连载”

  1. 这个连载很好~~~赞一个~~~~我用的MikTeX里面,有个ctangle,cweave~~~算是C语言版的吧~~~Knuth写的MMIX模拟器,编译起来,就要先用这两个来转化成c和tex的吧~~~

  2. Txyys: 是的,cweb 是 Knuth 和他的一个学生一起做的,Knuth 后来许多代码,比如 Stanford Graph Base,都是用 cweb 写的。

  3. 其实我始终没搞明白那个文学编程 web 语言的作用。 把 pascal 和 tex 写到一起 …… 然后需要的时候再用程序分开来 …… 而且我没觉得这样有多么易读和方便啊?

Leave a Reply

Your email address will not be published. Required fields are marked *