我处理过不少北航论文模板的编译问题,其中出现频率最高的,就是开头这几行黄色告警:
LaTeX Font Warning: Font shape 'TU/SimSun(1)/b/n' undefined(font) (font) using 'TU/SimSun(1)/m/n' instead on input line 42.第一次看到的同学基本都会慌:是不是模板坏了?是不是缺字体?但实际编译还能出PDF,正文也都在,只是所有本该加粗的汉字全都没有加粗。这个现象几乎是北航模板的“经典开场白”,而且不只是北航,很多基于ctexbook的学位论文模板都会踩到。这篇文章我不打算只给一条“复制粘贴就能跑”的配置,而是把告警的来源、字体加载机制、三条修复路线、以及在模板里具体改哪几行都讲透。如果你正在用北航模板写学位论文,或者准备把论文从 Windows 本地环境迁到 Overleaf,这篇应该能帮你省下大半天时间。
1. 告警原文拆解:TU/SimSun(1)/b/n 到底代表什么
1.1 一次典型的编译现场
用北航模板写论文时,最常规的编译命令是:
latexmk -xelatex main.tex或者直接多次运行:
xelatex main.tex然后控制台里就会出现这条“不打断编译、却让你心里咯噔一下”的字体警告。它通常出现在第一章或者目录之后,触发点往往是第一个\section、第一个\caption,或者任意一个\textbf{中文内容}。
这里的关键点:**它要求的是中文粗体,但对西文字体没有影响。**所以很多人一开始发现不了,直到检查 PDF 时才发现“怎么标题和正文一样粗?”
1.2 NFSS 字体形状的五个字段
要理解这条告警,得先知道 LaTeX 的字体描述体系。在 NFSS(New Font Selection Scheme)里,一个字体用编码/字族/字重/字形四段描述。这条告警拆开看是:
| 字段 | 值 | 含义 |
|---|---|---|
| 编码 | TU | XeLaTeX 下的 Unicode 字体编码 |
| 字族 | SimSun(1) | fontspec 加载的 SimSun 字体实例 |
| 字重 | b | bold,粗体 |
| 字形 | n | normal,常规字形 |
也就是说,LaTeX 在排版时发现:当前字体族SimSun(1)下,粗体常规字形TU/SimSun(1)/b/n不存在。它没有直接报错,而是自动往下降一档,用了TU/SimSun(1)/m/n,也就是中粗体(实际上就是常规字重)来替代。
m是 medium,中文里面通常就当常规字重看。所以这条告警的本质就是:SimSun 没有粗体,LaTeX 用普通宋体顶替了。
1.3 为什么这个告警不致命但很烦人
说它不致命,是因为论文还是能编译成功的,PDF 也能正常打开,内容不会少。说它烦人,是因为它带来的问题会在最后冲击盲审时集中爆发:
- 章节标题本来应该有层级感,结果一级二级标题和正文字重一样,目录里也看不出层级。
- 表格表头或关键词里的
\textbf完全无效。 - 摘要、图注里的中文粗体整体失效,导师一眼就能看出来。
- 更麻烦的是,
xelatex多编译几轮以后,日志文件里面全是这种警告,真正的报错信息反而被淹没。
所以那条using ... instead不是一句轻飘飘的提示,它是模板字体配置出问题的信号。接下来我讲讲这根因到底出在哪。
2. 根因分析:SimSun 为什么没有粗体,模板又是怎么踩上去的
2.1 中易宋体的字体文件只有常规字重
Windows 自带的简体中文字体里,SimSun(宋体)对应的字体文件是simsun.ttc。在系统中查看字体属性,你会注意到它的样式只有“常规”,没有“粗体”和“斜体”。中易宋体并不是一套包含多字重的字体家族,它只提供了一种正文字重。
这在日常 Office 软件里不明显,因为 Word 里你把中文设成“加粗”,本质上是用渲染引擎做了一个伪粗体。但 XeLaTeX 走的是另一条路:它通过 fontconfig 向系统查询字体信息,要看这个字体到底有没有真正的 bold 字重。查询结果是没有,于是它就不知道粗体该怎么办了。
2.2\setCJKmainfont{SimSun}只说明主字体,没说粗体用哪个
北航论文模板大多基于ctexbook文档类,常见配置会写成类似这样:
\documentclass[fontset=none, zihao=-4]{ctexbook} \setCJKmainfont{SimSun}这一行\setCJKmainfont{SimSun}的意思很简单:让中文主字体用宋体。但问题在于,它没有告诉 xeCJK“宋体没有粗体时该用什么”。于是 xeCJK 内部会试图为 SimSun 找一个粗体版本,找不到就发出了那条undefined(font)告警。
这就像一个界面设计稿上写了“这里放一个加粗的宋体”,但字体包里根本没有这个字重,排版软件只能拿普通宋体硬顶。
2.3 北航模板的“宋体标题”与\bfseries
北航的学位论文格式要求里,正文用宋体、章节标题用黑体是比较常见的规范。但不少模板为了省事,直接在标题格式里用了\bfseries。比如:
\ctexset{ section = { format = {\Large\bfseries}, } }这个\bfseries在英文排版语境下是“加粗”,但套用到中文宋体时,它就触发了上面说的粗体缺失链。如果模板在标题格式里使用的是\heiti或者\CJKfamily{zhhei},一般不会出现这个告警,因为它已经明确切换到黑体了。所以从根因上讲,这不是“XeLaTeX 有问题”,而是模板的字体语义没闭环。
2.4 为什么告警里是 SimSun(1) 而不是 SimSun
还有一个让很多人困惑的点:为什么字体名后面带个(1)?这不是北航模板专属,而是 fontspec 的内部机制。当一个字体在文档里被多次加载、或者同时作为CJKmainfont和某个CJKfamily的基础字体时,fontspec 会为它生成内部编号,用来区分不同实例。SimSun(1)就是第二个 SimSun 实例。
比如模板里同时写了:
\setCJKmainfont{SimSun} \setCJKfamilyfont{zhsong}{SimSun}或者某个宏包内部也加载了 SimSun,这时候就会出现SimSun(0)、SimSun(1)这种编号。看到(1)不要慌,它只是定位用的标签,真正要解决的是/b/n缺失。
3. 三条修复路线:黑体替代、伪粗体、换字体
3.1 路线A:把中文字体的粗体映射到黑体
我最推荐的方案,是直接告诉 LaTeX:中文粗体请使用黑体。
\setCJKmainfont[BoldFont=SimHei]{SimSun}这一行的意思是:中文主字体仍用宋体,但当需要加粗时,切换到黑体SimHei。这非常符合中文科技论文的排版传统——正文宋体、标题黑体,字重层次分明,而且不需要依赖任何伪造效果。
改动之后,\section、\textbf{中文}、\caption里的加粗中文都会变成黑体,告警也随之消失。如果你希望英文部分不受影响,也完全不用担心,\setCJKmainfont只管中文,西文字体由\setmainfont单独管理。
3.2 路线B:打开 AutoFakeBold 伪粗体
有些人希望“保持宋体外貌,只是变粗一点”,那就可以用伪粗体。xeCJK 提供了一个开关:
\setCJKmainfont[AutoFakeBold=2.5]{SimSun}或者全局设置:
\xeCJKsetup{AutoFakeBold=2.5}AutoFakeBold的原理不是调用真正的粗体字体文件,而是让排版引擎在渲染时对字形做加粗处理。参数2.5控制加粗程度,数字越大越粗,一般 2~3 之间比较合适。
这个方案的好处是改动最小,一行代码就能消掉告警。缺点也很明显:伪粗体本质是图形算法拉伸,不是真正的字体设计,在屏幕上看着还行,打印出来或转到高分辨率 PDF 后,笔画边缘会有点发“糊”,不够精致。如果你的论文要送盲审或正式归档,我对这种方案保留意见。
3.3 路线C:换成自带粗体的开源字体
如果不想碰伪粗体,也不想把中文粗体映射成黑体,那最干净的办法是换一套自带 Bold 字重的 CJK 字体。常见选择:
- FandolSong(ctex 宏包内置配套)
- Noto Serif CJK SC
- Source Han Serif(思源宋体)
比如:
\setCJKmainfont[BoldFont={Noto Serif CJK SC Bold}]{Noto Serif CJK SC}或者直接用 ctex 的字体集:
\documentclass[fontset=fandol]{ctexbook}这样整套中文排版都会换成开源字体,粗体、斜体都齐全,编译日志干净清爽。但这里有一个非常现实的坑:北航模板对中文字体有严格要求,很多学院明确要求“宋体”“黑体”“楷体”“仿宋”四件套,而FandolSong、Noto Serif CJK SC在字形上和中易宋体存在细节差异。正式提交前,最好先问清楚教务处或导师能不能接受。
3.4 三条路线横向对比
| 方案 | 代码成本 | 是否维持宋体 | 是否符合论文规范 | 风险点 |
|---|---|---|---|---|
| BoldFont=SimHei | 低 | 正文是宋体,加粗变黑体 | 推荐,符合标题黑体规范 | 如果导师要求“宋体加粗”,会有歧义 |
| AutoFakeBold | 极低 | 是,伪粗宋体 | 勉强通过 | 高分辨率下笔画发虚 |
| 换开源字体 | 中 | 否,字形有差异 | 需确认学院要求 | 可能影响提交格式一致性 |
从实际论文提交角度,我绝大多数情况会选路线A。它既保留了正文宋体,又让标题黑体化,和北航模板的格式要求天然一致。
4. 在北航模板的导言区落地修改
4.1 先定位模板里的字体配置代码
拿到一个北航模板,先不要急着大改,打开主.tex文件,按这些关键词搜索:
setCJKmainfontsetCJKsansfontsetCJKfamilyfontsetmainfontctexset
典型的北航模板导言区大概长这样:
\setCJKmainfont{SimSun} \setCJKsansfont{SimHei} \setCJKmonofont{FangSong} \setCJKfamilyfont{zhsong}{SimSun} \setCJKfamilyfont{zhhei}{SimHei} \setCJKfamilyfont{zhkai}{KaiTi} \setCJKfamilyfont{zhfang}{FangSong}如果你的模板长这样,那恭喜你,问题很明确。你只需要把\setCJKmainfont{SimSun}这一行改成:
\setCJKmainfont[BoldFont=SimHei, ItalicFont=KaiTi]{SimSun}这里顺带把ItalicFont配成楷体,是因为中文排版里习惯用楷体表示强调或引文,比真正的“倾斜”更像样。如果你确定不需要斜体,也可以只写BoldFont=SimHei。
4.2 最小可复现案例
为了说明问题,我给一个最小化案例。下面这段代码在 Windows + TeX Live 本地环境下,编译后必然出现开头那条告警:
\documentclass[fontset=none]{ctexbook} \setCJKmainfont{SimSun} \begin{document} \chapter{绪论} 中文粗体测试:\textbf{北航论文模板}。 \end{document}把\setCJKmainfont{SimSun}改成:
\setCJKmainfont[BoldFont=SimHei]{SimSun}再编译,告警消失,\textbf{北航论文模板}会以黑体渲染。这个最小案例可以用来快速验证你的 TeX Live 环境本身没有问题,再往北航模板里套。
4.3 容易漏掉的第二处配置:zhsong 字体族
如果你按 4.1 改了\setCJKmainfont,发现告警还在,那大概率是模板里用了\songti或\CJKfamily{zhsong}这类字体族命令。比如摘要的格式设置里可能写了:
{\songti 摘要标题}这时候 LaTeX 使用的是zhsong字体族,而不是CJKmainfont。你需要额外给它配置粗体映射:
\setCJKfamilyfont{zhsong}[BoldFont=SimHei]{SimSun}同理,如果模板里还有zhkai、zhfang这些族,也要检查它们是否会被用在需要加粗的场景。一般情况下黑体族zhhei不需要管,因为它本身就是标题字体;但楷体和仿宋如果被\textbf包裹,也会出现类似的 undefined 告警。
4.4 不推荐的做法
处理这个告警时,有几种做法我强烈不建议:
- 不要为了消除告警,在导言区写
\documentclass[fontset=windows]后,又手动覆盖字体。ctex 的fontset=windows本身已经把中文粗体映射成黑体了,你再覆盖反而可能重新引入问题。 - 不要把章节标题里的
\bfseries改成\textbf,两者对 CJK 来说走的是同一套字体选择机制,改完没用。 - 不要用
\pdfmapfile{}这类偏门命令去“绕”,XeLaTeX 根本不走 bitmap 字体映射那套流程。 - 更不要直接删除告警不处理,因为它本质是粗体失效,而不是多余提示。
5. 改完怎么验证,换环境后又怎么应对
5.1 三步验证法
改完配置后,不要只看“编译没报错”就完事,建议按三步验证:
查日志。重新编译后,在
.log文件里搜索undefined(font),如果搜不到SimSun相关的undefined(font),说明字体配置已经不再回退。看 PDF 字形。在 PDF 里找一个章节标题,用 PDF 阅读器的“属性”或“字体”面板检查它嵌入的字体。如果标题用的是 SimHei,说明
BoldFont=SimHei已生效。翻目录。目录里的章节标题往往单独有一套 TOC 格式,有些模板的目录字体设置和正文标题不同。如果目录里仍是普通宋体,说明模板在
toc格式里单独立了字体配置,还需要继续排查。
5.2 Overleaf、Linux 与老版本 TeX Live 的差异
北航模板在国内学生手里基本都是本地 Windows + TeX Live 编译,但如果你想放到 Overleaf 上写,环境差异会带来连锁问题。
Overleaf 的云端环境是 Linux,默认没有 SimSun、SimHei、KaiTi、FangSong 这些中易字体。你如果在 Overleaf 上仍然写\setCJKmainfont{SimSun},得到的将不是 undefined 告警,而是直接的The font 'SimSun' cannot be found。因为字体文件压根不存在。
在 Overleaf 上正确做法是使用 ctex 内置的开源字体集:
\documentclass[fontset=fandol]{ctexbook}或者手动指定:
\setCJKmainfont[AutoFakeBold=true]{FandolSong}另外要注意,不同版本的 TeX Live 里,ctex 宏包的默认行为也不完全一样。老版本 ctex 在fontset=none下对字体配置的解析可能更粗暴,如果你升级了 TeX Live 之后才出现告警,多半是宏包版本导致字体加载方式变化,而不是模板本身坏了。
5.3 举一反三的方法论
这条告警不只出现在北航模板,也不只出现在 SimSun 上。只要看到这种格式:
Font shape 'TU/字体名/b/n' undefined都可以按这个思路处理:
- 确认哪个字体被要求加粗。
- 去导言区搜索这个字体是以什么身份被加载的:是
CJKmainfont、CJKsansfont,还是CJKfamilyfont。 - 给对应的字体设置补上
BoldFont=...,或者打开AutoFakeBold。 - 重新编译并检查日志和 PDF 字形。
举例来说,如果以后看到TU/SimHei(1)/b/nundefined,那就是有人在黑体上又叠了一层\bfseries,这属于格式设置冗余,应该去改调用处的代码,而不是继续给黑体配粗体字体。如果看到TU/TimesNewRoman(1)/b/nundefined,则是西文字体缺粗体,需要去看\setmainfont的配置。
把这条方法论记下来,下次再碰到类似的字体回退告警,就不用再靠搜索答案碰运气了。
按照我处理北航模板这类问题的习惯,第一选择永远是BoldFont=SimHei,而不是AutoFakeBold。原因很简单:学位论文是正式存档文档,格式审查时导师和教务老师看的是 PDF 成品的视觉层级,伪粗体在屏幕上蒙混得过去,打印后笔画边缘容易发虚,到时候挨批评的还是你自己。另外一个小技巧:排查时在导言区加一行\listfiles,重新编译后.log文件末尾会列出所有加载的宏包版本和字体文件路径,这对定位“为什么我改了没生效”非常有用。最后想提醒一句,北航模板只是载体,真正要用好 XeLaTeX,还是得理解字体选择这一层。只有当你明白undefined(font)的意思是“缺字重而不是缺字体”时,这句告警才算真正被消化掉。