The State of wine on OS X

[wine][] 虽然声称自己是一个跨各平台的项目,可是它的 Mac OS X 支持一直很糟糕。因为最近 [ie4osx][] 的出现,原本对 wine 不感兴趣的人,如我又开始活络起来。今天花了一点时间理了理 wine 在 OS X 上的几个问题,简单记录如下,也许对别人有用。

[wine]: http://www.winehq.org
[ie4osx]: http://www.kronenberg.org/ies4osx

首先,wine 原本是不支持 Mac OS X 的,但独立的 [Darwine][] 项目很大程度上解决了这一点,可是 Darwine 项目自从去年十月份一来就再也没有更新过了,也没有给 x86 的二进制包发布。最近 ie4osx 的编译者提供了二进制包的下载,其实是来自[这里](http://thisismyinter.net/?p=21)编译的,然而这里提供的安装包中能用只有 x11drv,也就是说,wine 必须依靠 X11 才能运行,不能脱离 X11,像一个 native 的 OS X 应用程序那样运行。

[Darwine]: http://darwine.sourceforge.net

原本 [quartzdrv][] 也是 Darwine 项目中的一个分支,目标就是实现 native 的 OS X 支持,可惜出师未捷身先死,quartzdrv 目前也不能和最新的 wine 代码很好的兼容了。然而事实上,依赖 wine 开发的 [CrossOver Mac][] 这个项目早就完成了 quartzdrv 的改定,只不过这是一个商业项目,修改后的代码并没有公开,甚为遗憾。

[quartzdrv]: http://wiki.winehq.org/MacOSX/QuartzDriver
[CrossOver Mac]: http://www.codeweavers.com/products/cxmac/

所以一个好用的开源 quartzdrv 实现就成为了一直悬而未决的开发难题,现在 wine 的 git tree 中虽然有部分残余,其实是去年 Pierre d’Herbemont 发到 wine-patch 邮件列表的一系列 patch 中的第 [1](http://article.gmane.org/gmane.comp.emulators.wine.patches/29764), [2](http://article.gmane.org/gmane.comp.emulators.wine.patches/29766) 个,后续的 patch 一直未能合并进去,然而我咨询 Pierre 得到的回答是,他发的这一系列 patch 的功能仍然不能补足整个 quartzdrv 的需要。

我强烈建议有兴趣的同学,把这个开发的想法作为明年 [Google Summer of Code](http://code.google.com/soc/) 的项目。

话说回来,基于 X11 的实现在 Leopard 下会有一个 IE 页面频繁刷新的问题,通过更新 X11 到 [2.1.0](http://trac.macosforge.org/projects/xquartz/wiki/Releases) 版本可以解决。

对各平台文本渲染技术的一个简短的介绍

上周末参加 [thossclub](http://groups.google.com/group/thossclub) 的讨论,对各平台文本排版与渲染技术做了一个简短的介绍,这个介绍的 slides 可以在这里下载: [text-rendering-tech.pdf](http://jjgod.org/docs/slides/text-rendering-tech.pdf) (6.1 MB, PDF)

macports 在 Mac OS X 10.5 下编译 +universal 的一个问题

近来在开发一个小软件,需要分发程序链接了一些用 macports 安装的库,众所周知,用 macports 安装 universal binary 程序是通过 +universal 这个缺省 variant 实现的。在默认情况下,显然用户不愿意安装 universal 的,既然都在自己机器上编译了,去编译其他平台的二进制程序即浪费时间又浪费空间。所以默认这个 variant 是禁用的,可是如果你自己开发的 Universal Binary 应用要链接用 macports 安装的那些库时,就必须首先确保这些库是 universal binary。

可是在 10.5 下通过 +universal 之后,链接程序会遇到类似下面的错误:

$ sudo port install gettext +universal

—> Building gettext with target all
Error: Target org.macports.build returned: … returned error 2

gcc -dynamiclib -o … -L/opt/local/lib -lc
-isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386
-arch ppc -arch i386 -arch ppc -Wl,-framework -Wl,CoreFoundation
-install_name /opt/local/lib/libintl.8.dylib
-compatibility_version 9 -current_version 9.2
ld: library not found for -ldylib1.10.5.o
collect2: ld returned 1 exit status

这是什么原因呢?仔细看最关键的地方在于,macports 缺省使用了 `-isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc` 这个编译器参数来生成,可是在 Mac OS X 10.5 下,如果仅仅使用这个参数,系统仍然会以为你要编译的是 10.5 下运行的程序,所以最后会尝试链接 10.5 的 libc,问题是 10.5 的 libc 在 10.4 的 SDK 路径下当然找不到,于是就出错了。参考 [Xcode-Users 上的讨论][]。

[Xcode-Users 上的讨论]: http://lists.apple.com/archives/Xcode-users/2007/Oct/msg00686.html

怎么解决呢?也简单,加上 `-mmacosx-version-min=10.4` 这个编译参数就行了。不过对于 macports 来说,在哪儿加倒是一个问题,你可以针对每个 port,在 Portfile 里加上:

configure.universal_cflags-append “-mmacosx-version-min=10.4”

也可以一劳永逸地通过修改 `/opt/local/share/macports/Tcl/port1.0/portconfigure.tcl` 脚本中的 `default configure.universal_cflags` 实现,这里是一个简单的 [patch](http://trac.macosforge.org/projects/macports/attachment/ticket/13475/portconfigure.tcl.diff)。

这个 patch 已经发到了 macports 的 [trac](http://trac.macosforge.org/projects/macports/ticket/13475) 上,希望能尽快在官方版本中得到修复。

文档标记语言的一点思考

近来在水木上讨论文档标记语言的优劣,想起前些天查资料时正好又碰到了一个熟悉的名字: Scribe,于是多花了一点时间查找,没想到找到的资料仍然非常稀少。

Scribe,是 Brian Reid 在 Carnegie Mellon 的 Ph.D Thesis,也是对文档格式研究中所绕不开的一个重要的名字 (另一个,当然是 Don Knuth 的 TeX),这个项目大概在 1976 年开始,1980 年 Reid 发表这篇 [Scribe: A Document Specification Language and its Compiler](http://portal.acm.org/citation.cfm?id=909923) 以后,就甚少有什么改进了,尽管 Reid 的论文中也研究了 Knuth 的工作,但可以认为 Scribe 和 TeX 是同时代的作品。从对后续文档格式的影响说,Scribe 还更大一点,我们熟悉的 SGML (XML 的前身),BibTeX 都受了 Scribe 的影响。在 1982 年,Reid 还因为这一贡献 (Ground-breaking text-formatting language.) 获得了 [Grace Hopper Medal](http://hopl.murdoch.edu.au/showlanguage.prx?exp=2481)。

可是 Scribe 在应用上的成就却远远地被 TeX 所抛离,TeX 的生命力,被证明持久至今,而 Scribe 现在却在网上连一个正式的文档格式规范都找不到,一篇超过两页的详细描述都找不到!这是为什么呢?从 wikipedia 的文章中我们或许可以猜到一些隐情。

与 Knuth 慷慨地将 TeX 放入 public domain 不一样,1979 年 Reid 就把 Scribe 卖给了一个叫做 Unilogic 的公司,后来这个公司还持续和 Carnegie Mellon 大学就 Scribe 的知识产权问题扯皮,直到 CMU 放弃。最愚蠢的还不在这里,Scribe 居然在免费提供的 Scribe 程序中安插了后来被称为“time bomb”的东西,也就是说,90 天后如果用户不购买,这个软件就会执行自毁程序。

从 Scribe 如此猥琐的历史看,这个软件、这套格式最终为大众所抛弃,实在一点也不奇怪。

TeX Live 的新包管理架构

临近年末,TeX Live 2008 的发行就成为了一个有趣的话题,我们都知道 [TeX Live 2007][] 最大的改进是 [XeTeX][] 的集成,那 TeX Live 2008 呢,会有什么新东西?

[TeX Live 2007]: http://www.tug.org/texlive/
[XeTeX]: http://scripts.sil.org/xetex

[LuaTeX][]? 有可能,LuaTeX 恐怕是今年来在 TeX 引擎开发上的又一创新,不过虽然今年 LuaTeX 的底层代码已经有了很大的完善 (参考[这个](http://www.river-valley.tv/conferences/tex/tug2007/media/Hans_Hagen/)由开发者 Hans Hagen 在 TUG 2007 上的演讲),但上层结构: TeX 的排版格式定义:[Mark IV][] (下一代的 ConTeXt,基于 LuaTeX) 和 LuaTeX 兼容的 LaTeX2e 格式都未趋于稳定。当然,可能 LuaTeX 和相关格式会被包含在 TeX Live 2008 中,但多半会作为试验性特性来介绍。

事实上,自从 TeX Live 2007 发布后,TeX Live 的开发者们就开始讨论如何改进 TeX Live 的包管理架构,因为 TeX Live 无法像 MiKTeX 那样在线更新宏包是最为使用者所诟病的。毫无疑问,我们需要一个更灵活、更方便的包管理架构。今年 10 月的意大利 TUG 的会议 GuIT 2007 上,这个架构的主要开发者 Norbert Preining 就对此作了一个较为详细的介绍: [TeX Live’s New Infrastructure][]

[LuaTeX]: http://www.luatex.org/
[Mark IV]: http://wiki.contextgarden.net/Mark_IV
[TeX Live’s New Infrastructure]: http://www.river-valley.tv/conferences/guit2007/media/Norbert_Preining/

对急于想了解这个新架构大要的朋友,这里是我的一点理解。

在 2007 和以前的 TeX Live 中,使用 TPM 文件来组织软件包,这是一种 XML 格式的文件,有一套 Tpm.pm Perl 模块进行管理,TPM 的主要问题是:

* 混合了机器生成的动态信息和人工写入的静态信息
* 在许多不同的 TPM 中,同一个包的版本、授权和描述多次重复出现,来自不同时间的 TeX Catalogue 数据,因为缺乏及时的维护,导致很多数据事实上是过时的。
* 因为 TeX Live 使用 shell script 来安装软件包,而用 shell 来解析 XML 显然不现实,所以我们还需要从 TPM 文件生成 shell 比较好解析的 lists 文件

所以这套新的底层结构的目的是:

* 分离动态信息与静态信息
* 消除 lists 文件生成的必要
* 能够通过 web 安装单个软件包的更新
* 提供更好的文档组织,吸引更多围绕 TeX Live 的开发

最终的设计是这样的,围绕三种类型的文件进行开发: `tlpsrc`, `tlpobj` 和 `tlpdb`。

`tlpsrc` 是人工编辑的软件包描述文件,有包括 `name` (包名称), `category` (分类), `catalogue` (TeX Catalogue 名), `shortdesc` (短描述), `depend` (包依赖) 等诸项属性,每项都是简单的 UTF-8 文本,通过换行符分隔。

`tlpsrc` 中还通过 pattern 的形式描述安装这个软件包需要执行的操作,pattern 的设计主要为了描述的简洁和跨平台,详细内容可以看[这份文档](http://www.tug.org/svn/texlive/trunk/Master/tlpkg/doc/tlinfra-guit07.pdf)。

以 `latex.tlpsrc` 这个文件为例:

name latex
category Package
srcpattern d texmf-dist/source/latex/base
runpattern d texmf-dist/makeindex/latex
runpattern d texmf-dist/tex/latex/base
docpattern d texmf-dist/doc/latex/base

`tlpobj` 文件则是自动生成的,用于实际安装时的文件清单,类似如下:

name bin-dvipsk
category TLCore
revision 4427
docfiles size = 959434
texmf/doc/dvips/dvips.html

runfiles size=1702468
texmf/dvips/base/color.pro

texmf/scripts/pkfix/pkfix.pl
binfiles arch=i386-solaris size=329700
bin/i386-solaris/afm2tfm
bin/i386-solaris/dvips
bin/i386-solaris/pkfix
binfiles arch=win32 size=161280
bin/win32/afm2tfm.exe
bin/win32/dvips.exe
bin/win32/pkfix.exe

可以看出,这个文件的内容已经按照不同架构、不同类型组织好了,安装程序只需要按类别复制文件就可以了。

而 `tlpdb` 文件则是所有 `tlpobj` 文件的连接。

目前,TeX Live 的这套新结构已经完成了一个 Perl API 的参考实现,它将作为跨平台的 TeX Live 软件包安装程序的基础,但还有许多剩余的工作要做,包括改进效率、转换原来的 ctan 描述为新的 `tlpsrc` 描述,等等,而我目前在开发的是一套 C 的 API,目的是方便其他语言 binding 的开发,统一实现细节,并提供最好的处理性能。

如果你有兴趣,可以参考:

* [如何更新 TeX Live 中的软件包描述](http://www.tug.org/texlive/pkgupdate.html)
* [相关代码和文档](http://www.tug.org/svn/texlive/trunk/Master/tlpkg)
* 我正在开发中的 [C 实现](http://www.tug.org/svn/texlive/trunk/Master/tlpkg/lib/C/)