装好 LaTeX,你同时也装进了一座图书馆。数一数 TeX Live 2024 的 texmf-dist/doc,这些全部来自 CTAN(Comprehensive TeX Archive Network)的文档有 10,099 份 PDF,整棵目录树共 3.7 GB,而其中大部分从未被打开过一次。打开本机副本的钥匙,是 texdoc 这一个词的命令。本页讲这座归档站是怎么运转的,以及更有用的一件事:如何阅读你已经拥有的文档——texdoc、kpsewhich、tlmgr info,以及从 .dtx 源码重新排出说明书。
texdoc 宏包名——一秒打开本机的说明书
输入 texdoc booktabs,本机所装 booktabs 的说明书 PDF 就直接打开了。这不是网络搜索,而是磁盘上的文件。这一点很重要,因为打开的是与你已装版本对应的文档:网上找到的文章可能停留在两代之前的写法,而 texdoc 给你的 PDF 描述的正是你自己的环境。默认是 view 模式,即打开工具判定为最佳的那一个结果。加选项可以改变行为:-l 列出候选并让你按编号挑选,-m 在只有一个好结果时直接打开、否则给出菜单,-s 连平时被隐藏的低分结果也一并显示。
texdoc booktabs # open the manual for the version you have installed
texdoc -l siunitx # list every candidate, then pick one by number
texdoc -I -l booktabs # plain list, no interactive prompt
texdoc -M -l lshort # machine-readable: name, score, path, language
texdoc bootabs # a typo still finds booktabs (fuzzy search)texdoc 的聪明之处在于它不只按文件名匹配。除了遍历文档树(TEXDOCS 路径),它还查询 TeX Live 数据库 texlive.tlpdb,因而能够顺着包含 名字.sty 或 名字.cls 的宏包找下去。所以 texdoc shortvrb 会正确打开 latex 宏包里的 doc.pdf——因为默认配置文件中写着 alias shortvrb = base/doc。候选结果会被打上数值分数:叫 名字.pdf 的得分高,Makefile 则被压低 -1000。即使拼错,只要完全没有匹配,它还会改去寻找最接近的宏包名,所以 texdoc bootabs 依然落到 booktabs 的说明书上。真的找不到时的提示是 Unfortunately, there are no good matches for "...",随后给出 texdoc.org 上同名文档的指引。
| 选项 | 作用 | 适用场合 |
|---|---|---|
(none) | 用查看器打开最佳的一份 | 已知宏包名时;这是默认行为 |
-l | 列出候选并提示输入编号 | 除说明书外还带示例或技术说明的宏包 |
-m | 只有一个好结果时打开,否则列表 | 日常使用的折中选择 |
-s | 显示全部,包括低分结果 | 想看 README 或 CHANGES 时 |
-I | 输出纯列表,不出现交互提示 | 写脚本或想贴进日志时 |
-M | 以制表符输出名称、分数、路径、语言 | 供其他工具消费;隐含 -I |
-f | 列出正在使用的配置文件 | 想确认个人设置该写在哪里时 |
还有一个机制对多语言读者很有用:texdoc 会从系统区域设置推断你的语言,并给 名字-语言代码.pdf 加分。执行 texdoc -l booktabs,在英文的 booktabs.pdf 之外还会出现 booktabs-de 和 booktabs-fr 两个目录——这些译好的说明书本来就随 TeX Live 一起发行。同理,texdoc -l lshort 会返回六十多条结果,各语言版本排在前面,带着 [fr]、[zh]、[ko] 之类的标记。若自动判断不准,可在个人配置文件里写一行 lang = zh 固定下来(texdoc --files 会告诉你该文件在哪,macOS 上是 ~/Library/texmf/texdoc/texdoc.cnf)。在同一个文件里写 mode = list,此后每次调用就相当于都加了 -l。
那个 .sty 究竟在哪——kpsewhich 与 tlmgr info
kpsewhich booktabs.sty 会用一行返回 LaTeX 实际会读取的那个文件的绝对路径。当文档的行为与说明书对不上时,首先该怀疑的不是版本,而是「正在读的文件也许不是你以为的那个」,而这条命令一次就能确认。再加 --all,就会按搜索顺序列出所有候选。试试 kpsewhich --all article.cls,会返回两行:texmf-dist/tex/latex/base/article.cls 和 texmf-dist/tex/latex-dev/base/article.cls。同名文件互相遮蔽的情形就这样看得见了。如果你曾自己写过 .sty 并放进主目录,请怀疑 kpsewhich -var-value=TEXMFHOME 返回的那个目录(macOS 上是 ~/Library/texmf)。找不到文件时它不输出任何内容并以退出码 1 结束,因此也可以直接用在脚本的条件判断里。
kpsewhich booktabs.sty # which file will TeX actually read?
kpsewhich --all article.cls # every copy, in search order
kpsewhich -var-value=TEXMFHOME # your personal tree
tlmgr info booktabs # version, licence, collection, sizes
tlmgr info --list booktabs # run / source / doc files, one by onetlmgr info booktabs 回答的是另一个问题:不是「在哪」,而是目录里怎么写的。你会得到一行简介、长描述、所属集合、许可证(lppl1.3c)、src / doc / run 各部分的体积,以及版本号。有时还会出现 cat-contact-bugs 和 cat-contact-repository,那就是该宏包问题追踪器的地址。执行 tlmgr info --list booktabs,文件本身会分成三组列出——而这三组正是 TeX Live 的目录布局:tex/latex/booktabs/booktabs.sty(运行时读入的本体)、doc/latex/booktabs/booktabs.pdf(texdoc 打开的说明书),以及 source/latex/booktabs/booktabs.dtx 及其 .ins(前两者的来源)。
| 目录 | 里面是什么 | 怎么找 |
|---|---|---|
texmf-dist/tex/ | \usepackage 载入的 .sty 与 .cls;TeX Live 2024 中有 6,296 个 .sty | kpsewhich booktabs.sty |
texmf-dist/doc/ | 说明书;PDF 有 10,099 份,整棵树 3.7 GB | texdoc booktabs |
texmf-dist/source/ | .dtx 与 .ins 源码;TeX Live 2024 中有 2,746 个 .dtx | tlmgr info --list booktabs |
TEXMFHOME | 你自己放的 .sty 与配置;优先于发行版,因而常是意外之源 | kpsewhich -var-value=TEXMFHOME |
.dtx 与 .ins——源码本身就是说明书
.dtx 是把代码和讲解装进同一个文件的格式,而同一个文件可以有两种处理方式。运行 tex 宏包名.ins,docstrip 会丢掉讲解行、写出 .sty;运行 pdflatex 宏包名.dtx,则是把代码逐行加注排版出来,成为说明书 PDF。在本机拿 multirow 试过:tex multirow.ins 生成了 multirow.sty、bigstrut.sty、bigdelim.sty 三个文件,pdflatex multirow.dtx 排出了 30 页的带注释源码。好处在于,你可以追查 texdoc 说明书里没写的行为——实现就在眼前,「为什么这个选项会这样」可以一直读到底。
# copy the two source files out of the tree first, then:
tex multirow.ins # docstrip: writes multirow.sty, bigstrut.sty, bigdelim.sty
pdflatex multirow.dtx # the same .dtx typeset as an annotated source PDF
pdflatex multirow.dtx # run twice so the cross-references settle这套机制的极致例子就是 LaTeX 本身。执行 texdoc source2e 会打开《The LaTeX 2ε Sources》——署名包括 Johannes Braams、David Carlisle、Alan Jeffrey、Leslie Lamport、Frank Mittelbach 等人的1,308 页带注释内核全文。而一旦养成读文档的习惯,你会开始注意到有趣的细节。tlmgr info booktabs 报出的版本号是 1.61803398——那是黄金比例 φ = 1.618033988… 的数字,每发布一次就多一位,booktabs.dtx 里也自陈“(converging to phi, the golden ratio)”。把版本号做成一个数列是个玩笑,但只有打开 .dtx 才能确认这是玩笑。
CTAN 是什么——1992 年建起的一个地址
CTAN(Comprehensive TeX Archive Network,ctan.org)的存在,是为了让 TeX 相关材料只有一个存放地点。它由德国的 Rainer Schöpf 与 Joachim Schrod、英国的 Sebastian Rahtz,以及美国的 George Greenwade 于 1992 年建立——名字正是 Greenwade 起的——并在 1993 年英国 Aston 的 EuroTeX 会议上正式发布;这个构想本身可追溯到 1991 年的一场讨论。在此之前,宏与字体散落在各个 FTP 站点,不同的人一次次各自重新收集同样的东西。所以 CTAN 解决的问题不是「没地方放」,而是「地方太多」。
今天进入 CTAN 的入口是宏包页面 ctan.org/pkg/<name>。上面列有 Sources(源码)、Documentation(PDF)、Version、Licenses、Copyright、Maintainer、Contained in(是否收录于 TeX Live / MiKTeX)以及 Topics(主题分类)。实务上最有用的是后两项。看 Contained in 就立刻知道能否用 tlmgr install 装,还是必须手工安装。Topics 则是「不知道名字但知道功能」时的入口,比如要找表格相关的宏包,可以从 table 主题顺藤摸瓜。许可证一栏几乎都是 LPPL(LaTeX Project Public License),那是 TeX 世界关于再分发与修改的标准条款。
「Network」这个词不是装饰。CTAN 由一个核心站点和分布全球的官方镜像组成,镜像自动同步(目前运行一个镜像大约需要 50 GB 磁盘)。因此在下载地址里写 mirror.ctan.org,就会被自动分配到就近的镜像——TeX Live 官方指南也明确写着,默认的宏包仓库是通过 https://mirror.ctan.org 自动选出的 CTAN 镜像。若想固定到某个镜像,列表在 ctan.org/mirrors。反向的流动同样存在:作者把新增或更新的宏包上传到核心站点的收件区,经 CTAN 团队处理后再传播到各镜像。连协助投稿的工具都随 TeX Live 一起发行——ctanify 会按 CTAN 偏好的结构打包,ctan-o-mat 则在寄出前先做校验。而 TeX Live 本身就是「CTAN 的快照」:你磁盘上那 3.7 GB 文档,正是这座归档站的副本。
本地文档与在线文档,该信哪一个
决定你的文档能不能编译通过的,是你本机的那份文档。 所以在追问「为什么跑不起来」时,请先打开 texdoc。反过来,若想知道「这个功能加进去了吗」,就该去看 CTAN 的宏包页面或 texdoc.org——那边始终是最新的。两者确实会出现落差。TeX Live 的每个版本最终都会冻结,之后的更新会进入下一个版本,所以 tlmgr info 报出的版本号与主题分类比 CTAN 上显示的旧,是很常见的事。发现落差时,稳妥的顺序是:先用 tlmgr info <宏包名> 确认自己的版本,再与 CTAN 上的描述对读。网上找到的代码跑不通,相当多的情况并不是文章过时,而是你的环境与作者的环境不同。