TeX 安装是一堆数以万计的文件——宏、类、字体、配置。为什么写入单行 \usepackage{amsmath} 可以可靠地在磁盘上的某个位置找到 amsmath.sty ?它背后有两个约定:文件所在位置的标准(TDS)和查找文件的机制(kpathsea)。该页面绘制了该地图。
TDS:一切事物的标准场所
一切都从一个名为 texmf 树 的目录树开始 - “texmf” 是 *TeX 和 Metafont* 的缩写。在它下面,文件按 kind 分支:宏和类位于 tex/ 下,任何与字体相关的内容位于 fonts/ 下,书目数据位于 bibtex/ 下,文档(手册)位于 doc/ 下,脚本位于 scripts/ 下。在每个系统中标准化此布局是 TDS (TeX Directory Structure) 的工作,由 20 世纪 90 年代的 TeX Users Group (TUG) 定义。
为什么要有一个标准? TeX 在 macOS、Unix、Windows 等上运行,并且 CTAN(Comprehensive TeX Archive Network)收集大量软件包。如果每个站点以不同的方式排列文件,那么运送包裹的人和查找包裹的工具每次都会出错。一旦修复了“tex/ 下的宏”,就可以在任何 OS 和任何发行版上仅从规则推断出任何文件的位置。便携性正是 TDS 解决的问题。
分支机构有自己的规则。 tex/ 按格式拆分,然后按包拆分,得到 tex/<format>/<package>/(其中 <format> 是 latex、plain、generic,...)。例如,标准 article.cls 位于下面的路径 - 稍后介绍的 kpsewhich 工具将报告您自己计算机上的完全相同的位置。
$ kpsewhich article.cls
/usr/local/texlive/2026/texmf-dist/tex/latex/base/article.cls字体更精细了一级:fonts/<type>/<supplier>/<typeface>/。 <type> 是一种文件 — tfm 表示 TeX 字体规格,vf 表示虚拟字体,加上 type1、opentype、truetype 等。 <supplier> 是提供它的人(public、adobe、ams 等),<typeface> 是字体名称(cm = Computer Modern)。下表列出了您最常遇到的分支以及每个分支的含义。
| 目录 | 它包含什么 |
|---|---|
tex/ | 宏、类、样式(.tex .sty .cls);例如tex/latex/... |
fonts/ | 所有字体文件,按类型:tfm、vf、type1、opentype、enc、map,... |
bibtex/ | 参考书目数据库 bib/ 和样式 bst/ |
doc/ | 软件包手册和文档(texdoc 打开的内容) |
scripts/ | OS独立的可执行脚本(mktexlsr的主体等) |
web2c/ | 发动机配置; texmf.cnf 和格式定义的主页 |
多棵树,哪一棵获胜
texmf 树不是一件事。 TeX Live 捆绑了多个具有不同角色的树,每个树都由 TEXMF… 变量命名。为什么要把他们分开?要区分三件事:分布(只读,每次更新时批量替换),您添加的内容(不得消失)和自动生成的工作数据。混合它们,更新发行版可能会立即消除您自己的风格。
| 多变的 | 角色和默认位置(例如 TeX Live 2026) |
|---|---|
TEXMFDIST | 发行版本身;大部分包裹。 请勿触摸。 .../texlive/2026/texmf-dist |
TEXMFLOCAL | 站点范围内的添加,由所有用户共享。 .../texlive/texmf-local |
TEXMFHOME | 您的个人树;您自己的风格和类别都在这里。默认值:Linux 上的 ~/texmf、macOS 上的 ~/Library/texmf、Windows 上的 %USERPROFILE%\texmf |
TEXMFVAR | 自动生成的缓存(格式、字体……);从不手动编辑 |
TEXMFCONFIG | 每用户配置存储(由 updmap 等编写) |
TEXMFSYSVAR / SYSCONFIG | 上述 VAR / CONFIG 的系统范围对应项 |
TEXMFROOT | 整个安装的根目录。 .../texlive/2026 |
如果同名文件存在于多棵树中,哪一个获胜?这是由 TEXMF 变量决定的,它只是按顺序列出搜索优先级。查询它大致返回以下序列(最左边的获胜):
$ kpsewhich -var-value=TEXMF
{$TEXMFCONFIG,$TEXMFVAR,$TEXMFHOME,!!$TEXMFLOCAL,!!$TEXMFSYSCONFIG,!!$TEXMFSYSVAR,!!$TEXMFDIST}像这样阅读:首先是您自己的配置(TEXMFCONFIG)和工作数据(TEXMFVAR),然后是您的个人树 TEXMFHOME,然后是站点范围的 TEXMFLOCAL,最后是系统配置、工作数据和分布 TEXMFDIST。由于这个顺序,将您自己的 mystyle.sty 放入 TEXMFHOME 会使其影响发行版的副本 - 没有破坏,只是个人 → 站点 → 发行版的自然排名。 (前导 !! 将在下一节中解释。)
kpathsea:如何找到文件
即使布局固定,谁能真正找到文件?这就是 kpathsea (kpse,*kpath 搜索*) — 由 TeX 及其配套工具共享的路径搜索库。 tex、pdflatex、dvipdfmx,其余不自行搜索;他们都问kpathsea,“amsmath.sty在哪里?”
kpathsea 将搜索路径表示为具有规则的字符串。三个符号值得了解: $VAR 扩展变量;尾随 // 表示“递归搜索此以下的所有内容”;前导 !! 表示“不要直接扫描磁盘 - 仅查阅下面描述的文件名数据库。”** 查找 LaTeX 源 TEXINPUTS 的路径实际上如下所示:
$ kpsewhich -var-value=TEXINPUTS
.:$TEXMF/tex/{latex,generic,}//读作:先查看.(当前目录);如果做不到这一点,请按照 latex → generic → 其他所有内容的顺序递归遍历每个 texmf 树的 tex/ 分支。这给出了您所期望的直观行为 - 手稿旁边的文件获胜,否则回退到发行版。
但真正每次扫描数以万计的目录会太慢。因此 kpathsea 使用一个名为 ls-R 的 文件名数据库,该数据库放置在每棵树的根部 — 哪个文件位于哪个目录中的文本列表。查询该索引而不是遍历磁盘使查找变得即时。前面看到的 !! 的意思是“只信任索引(永远不要接触真正的磁盘)”,它像分布一样附加到树上,很少改变。
另一方面:将文件添加到树后,TeX 可能无法找到它,直到重新构建 ls-R - 特别是在 !! 系统树中。重新生成索引的命令是mktexlsr,也称为texhash。像 TEXMFHOME 这样的个人树受到更宽松的对待,通常不需要重建,但在将某些内容放入 TEXMFLOCAL 后,安全的做法是运行下面的一行。
# Rebuild the ls-R filename databases after adding files to a tree
$ mktexlsr # texhash is an exact alias当出现问题时,第一步是直接使用 kpsewhich 查询文件和变量:“实际上正在读取哪个文件?”以及“这个变量扩展到什么?”立即得到答复,让您隔离错误配置。整套 kpsewhich 选项以及 tlmgr 等管理命令在单独的页面上详细介绍。
PATH:命令之路
kpathsea 找到文件 TeX 读取,但在此之前 shell 必须找到 可执行文件本身,pdflatex。这就是 OS 的工作:它按顺序搜索 PATH 环境变量中列出的目录。 TeX Live 将其可执行文件保存在单个每个 OS、每个架构的 bin 目录中,并将其放在 PATH 上是安装的最后一步。
目录名称嵌入年份和平台:on Linux /usr/local/texlive/2026/bin/x86_64-linux、on macOS /usr/local/texlive/2026/bin/universal-darwin、on Windows ...\bin\windows。在 macOS 上,MacTeX 在 /Library/TeX/texbin 上提供独立于年份的稳定符号链接,因此每年升级不需要对 PATH 进行编辑。您可以看到它当前指向的内容,如下所示:
$ which pdflatex
/Library/TeX/texbin/pdflatex
$ readlink /Library/TeX/texbin
Distributions/Programs/texbin如果您看到“pdflatex: command not found”,那么十分之九的情况就是 PATH 中缺少 bin 目录。 OS-by-OS 的设置过程以及安装后检查均保留在安装页面中。
texmf.cnf:设置的来源
到目前为止,所有变量——TEXMF、TEXINPUTS、每棵树的位置——实际上来自哪里?答案是一个名为 texmf.cnf 的配置文件。在执行任何操作之前,kpathsea 会读取它以获取操作参数:搜索路径、每棵树所在的位置、内存限制等等。主副本位于发行版的 web2c/ 下:
$ kpsewhich texmf.cnf
/usr/local/texlive/2026/texmf.cnf有趣的部分:可以有多个 texmf.cnf。 kpathsea 按顺序从专用搜索路径(TEXMFCNF 变量)上的多个位置读取 texmf.cnf,并采用它为任何给定变量找到的第一个定义(后面的文件不会覆盖前面的文件)。因此,您可以保持发行版的大默认文件不变,并将一个小的覆盖文件放在优先级较高的位置 - 这是一种仅安全地添加您的更改的分层方案。添加 -all 显示实际堆积的文件:
$ kpsewhich -all texmf.cnf
/usr/local/texlive/2026/texmf.cnf
/usr/local/texlive/2026/texmf-dist/web2c/texmf.cnf这里,上面的 texmf.cnf(TeX Live 的精简覆盖)是在下面的 texmf-dist/web2c/texmf.cnf(数百行默认值)之前读取的。当您想要永久更改某个值时,惯例不是编辑发行版的文件,而是仅将您需要的行写入更高优先级的位置,例如 TEXMFLOCAL/web2c/texmf.cnf。这样做,您的设置就可以在发行版升级后继续存在。
总而言之,TeX 查找文件的方式如下:texmf.cnf 首先修复树的位置以及搜索路径的样子;按照该顺序,kpathsea 定位目标(通常通过 ls-R 索引); PATH 提供可执行文件本身的入口点。这三层相互啮合,从而形成一条线 \usepackage{...} 静静地解析。
自己的文件放在哪里
最重要的实用规则是:不要编辑分发树。如果您将仅限论文的 thesisstyle.sty 或实验室范围的 labreport.cls 放入 /usr/local/texlive/2026/texmf-dist 中,则更新或重新安装可能会将其删除。将个人文件放在 TEXMFHOME 中,将实验室范围的文件放在 TEXMFLOCAL 中,并保留 TDS 布局。
相比之下,仅属于一个提交包(会议 myconf.cls 或期刊 journal.sty)的文件可能位于手稿旁边。 TEXINPUTS 首先检查当前目录,因此 TeX 会更喜欢该副本。这也是为什么在手稿旁边放置 article.cls 或旧的 amsmath.sty 等通用名称是危险的:它会影响发行版并产生仅出现在其他机器上的故障。
# 個人用スタイルを TEXMFHOME に置く例
mkdir -p ~/texmf/tex/latex/thesisstyle
cp thesisstyle.sty ~/texmf/tex/latex/thesisstyle/
# TeX がどれを拾うか確認する
kpsewhich thesisstyle.sty一旦 kpsewhich 报告了你期望的路径,手稿就可以简单地说 \usepackage{thesisstyle}。如果没有报告任何内容,请按顺序检查:文件是否位于 tex/latex/<package>/ 下、文件名大小写是否匹配以及 mktexlsr 是否针对系统树运行。这将失败描述为“我把它放在搜索地图的什么位置了?”而不是“TeX 坏了”。