Windows 下编译 Poppler PDF 库:MSYS2 与 CMake/Meson 实战指南
最近在整理一套本地文档处理工具链的时候需要在 Windows 10 客户端里完成 PDF 的文本抽取、页面渲染成图片、元数据读取这几件事。调研一圈后发现能免费商用的 PDF 库本就不多Poppler 作为老牌开源渲染库几乎没有替代品但官方偏偏不维护 Windows 的预编译二进制于是只能自己动手编。网上关于 Poppler 编译的教程大半是 Linux 环境的Windows 的要么年代久远要么语焉不详我前后折腾了两三天才把整套流程稳定跑通。这篇文章把完整方案写出来包括环境搭建、依赖选型、CMake 和 Meson 两套构建系统的配置、高频报错排查、以及编译产物最后的集成验证。适合自己维护 PDF 工具的开发者、需要做 PDF 转图或文本抽取的工程师、以及想把 Poppler 接进 Qt 项目的同学。我不光贴命令每一步为什么这么做也会讲清楚这样你遇到我当年踩过的坑时能更快绕过去。1. 编译前先搞清楚你拿 Poppler 要做什么1.1 Poppler 到底是什么先亮底牌Poppler 是从老牌 PDF 查看器的基础上派生出来的开源渲染库很多你叫得出名字的开源文档工具底层其实就是它。它提供的能力相当完整PDF 页面光栅化渲染、文本内容抽取、文档属性和书签读取、表单填写、注释解析、多份 PDF 合并拆分等等。在 Linux 生态里大部分发行版都内置了预编译的 poppler-utils 工具集也就是 pdftotext、pdfinfo、pdftoppm、pdftocairo 这一整套命令行工具常年是服务器端文档处理管线的标配。Windows 上的情况就完全不一样了。官方只发布源码基本不维护 Windows 的预编译包。你在网上能找到的一些所谓Windows 版 Poppler要么是第三方爱好者编译的旧版本要么打包方式来路不明版本功能和依赖状态都不可控。对于要进生产环境的工具链来说这种不确定性往往就是最大的风险点。所以自己编译不只是为了有得用更是为了把依赖版本、功能开关、链接方式这些变量全部握在自己手里。后面接进自己项目的时候出任何问题都能顺着源码和配置查到底。1.2 为什么非要自己编译不直接用现成方案有人可能会问Windows 上处理 PDF 不是有一堆现成库吗为什么偏偏要编译 Poppler这里有几个非常现实的原因。首先很多商业 PDF 库是按授权点收费的哪怕只是内部工具也得走采购流程成本和合规都很麻烦。开源项目里单纯解析 PDF 内容的库不算少但要做到页面渲染成高清图片、带抗锯齿、支持复杂版式这种偏 GUI 的场景Poppler 几乎是性价比最高的选择。它内置了轻量级的 Splash 渲染后端也可以接 Cairo 这种工业级 2D 绘图库灵活度比大多数同类项目高一个量级。其次自己编译意味着可以按需定制。我实际做项目时需要裁掉用不到的功能模块来缩小体积也需要把 JPEG2000 支持、色彩管理、数字签名这类可选项明确打开。这些在别人编译好的二进制里根本做不到。做二次开发的同学还有个隐藏需求带调试符号的版本。线上程序崩溃时能定位到库内部的行号和只能看到一堆地址是完全两种调试体验。还有个很多人忽略的点预编译二进制的动态链接依赖通常是一笔糊涂账。Windows 下跑 Linux 风格的开源程序DLL 版本对不上是家常便饭。自己从源码编译至少能清楚它链了哪些库、每个库什么版本排障的时候能顺着依赖图一步步查。说白了自己编译的隐性收益是可控性这在把库往正式系统里集成时比什么都重要。1.3 两条主流编译路线怎么选在 Windows 10 上编译 Poppler业内实践下来主要有两条路线一条是 MSYS2 加 MinGW-w64 工具链另一条是 Visual Studio 加 vcpkg 包管理。这两条路线我都实际跑过最终长期用的是 MSYS2 方案下面把取舍理由和对比情况摊开说。对比项MSYS2 MinGW-w64Visual Studio vcpkg依赖获取pacman 一键安装依赖天然兼容vcpkg 可装但版本组合要自己调编译速度较快依赖现成无需重复构建首次要全量编依赖时间翻几倍与 MSVC 工程集成C ABI 可直接用C 接口需适配原生无缝调试体验最好可复现性高脚本化容易中依赖库版本易变总体工作量低中高MSYS2 的核心优势是把一整套 POSIX 生态平移到了 Windows 上。Poppler 的大量依赖——fontconfig、glib、cairo 这些——骨子里是为 Linux 设计的在 MSYS2 里它们的 pkg-config 文件现成CMake 或 Meson 能自动找到所有依赖几乎不需要针对 Windows 做特殊适配。vcpkg 路线不是说走不通而是你要为每个依赖分别编译不同配置工程量明显更大而且个别库在 vcpkg 上的版本滞后会导致新版 Poppler 编译直接失败。如果你后续必须用 Visual Studio 调试整个 Windows 程序那选 vcpkg 更合理如果只是想把 Poppler 跑起来并集成进自己项目MSYS2 是省时间的正解。2. 环境准备MSYS2 和依赖包一次配齐2.1 安装 MSYS2 和基础工具链MSYS2 的安装本身没什么门槛从项目官网下载安装包一路下一步即可。装完之后你会在开始菜单里看到好几个入口 shell包括 MSYS2 MSYS、MSYS2 MinGW64、MSYS2 MinGW32。这里藏着一个新手最容易踩的坑编译 Poppler 以及它的绝大多数依赖必须用 MinGW64 那个 shell因为我们要生成的是原生 64 位 Windows 程序。简单解释一下这个环境的角色分工MSYS 环境像一层翻译层提供 Unix 风格的命令和路径但它产出的程序带有 MSYS 运行时依赖脱离 shell 后在纯净 Windows 上很难跑起来。而我们真正要的是 MinGW-w64 工具链生成的原生程序所以一切操作都以 MinGW64 shell 为准。很多人第一次在这里犯迷糊以为在哪个 shell 里装 gcc 都一样结果编出来的库要么是 32 位要么带了额外的运行时依赖后患无穷。进了 MinGW64 shell 之后先做一轮系统更新和基础工具安装pacman -Syu pacman -S --needed base-devel gitbase-devel 这个包组最容易被人跳过但它里面含有 make、autoconf、automake、pkg-config 这些辅助工具。Poppler 虽然主要靠 CMake 或 Meson 构建但它的某些辅助脚本和依赖构建过程仍会调用这些 POSIX 工具缺了它们会在莫名其妙的环节报错到时候排查起来很头疼。2.2 依赖包怎么选每个是干什么的Poppler 的构建依赖可以分成三类核心渲染类、字体处理类、可选增强类。用 pacman 一键安装是最省事的方式我在实际编译时用到了下面这组包# 编译器和构建系统 pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja # 基础依赖 pacman -S mingw-w64-x86_64-pkgconf pacman -S mingw-w64-x86_64-freetype mingw-w64-x86_64-fontconfig pacman -S mingw-w64-x86_64-libpng mingw-w64-x86_64-libjpeg-turbo pacman -S mingw-w64-x86_64-lcms2 mingw-w64-x86_64-libtiff pacman -S mingw-w64-x86_64-openjpeg2 # GLib 和 Cairo按需开启 pacman -S mingw-w64-x86_64-glib2 mingw-w64-x86_64-cairo每个包的角色我简单交代一下方便你按实际场景裁剪。freetype 和 fontconfig 是字体处理的核心PDF 里几乎所有字体渲染都绕不开 freetypefontconfig 负责字体发现与匹配它决定了渲染时能不能正确找到系统字体。libpng、libjpeg-turbo、libtiff 是图像编解码库PDF 内嵌的位图资源全部走它们。lcms2 做色彩管理如果你要处理带 ICC 色彩配置文件的 PDF这个必须开否则色彩会偏。openjpeg2 负责 JPEG2000 压缩图片的解码医疗影像 PDF、高清扫描件 PDF 大量使用这种编码缺了它页面会显示成空白块或者乱码区。GLib 和 Cairo 这两个要单独说。GLib 是给 Poppler 的 GLib 风格 C API 用的很多 C 语言项目通过 poppler-glib 接口接入不装的话得在配置阶段关掉相应选项。Cairo 是高级渲染后端pdftocairo 工具能把 PDF 页面转成 PNG、SVG、PS 等格式依赖的就是它。如果你只需要简单文本抽取这两个确实可不开但只要涉及把 PDF 页面变成一张图Cairo 和 GLib 就是标配。装完后顺手验证一下依赖是否齐全pkg-config --modversion freetype2 fontconfig cairo glib-2.0 libopenjp2如果每个都输出了版本号说明依赖准备完毕。缺谁补谁这一步值得花五分钟确认后面构建系统配置阶段能省大量排查时间。2.3 环境验证下手前先确认三件事正式编译之前我习惯做三个小检查能避免大把无效劳动。第一确认当前 shell 确实是对应架构的 MinGW64 环境。执行echo $MINGW_PREFIX如果输出是/mingw64就对了。如果输出是/usr或者直接为空说明你开的是 MSYS shell得换窗口重来不然构建系统大概率会找到一套奇怪的编译器组合。第二确认 gcc 的架构目标。执行gcc -dumpmachine输出应该带x86_64-w64-mingw32字样。有些机器之前装过别的 GCCPATH 里残留的编译器会把构建系统带偏编译到一半才爆出诡异的链接错误这种问题最隐蔽。提前三十秒确认能省一小时。第三确认cmake和ninja都来自 MSYS2。如果电脑上装过 Visual Studio系统 PATH 里可能有另一套 CMake。在 shell 里执行which cmake路径应该指向 MSYS2 的安装目录指向别处的话优先把/mingw64/bin调到 PATH 最前面。提示MSYS2 环境里路径有两种写法Windows 风格是C:/xxxMSYS 风格是/c/xxx两者都能用。但构建系统传给编译器的路径往往被转成 Windows 风格看到奇怪的路径拼接报错时先想想是不是路径风格混用导致的。3. 正式编译从构建系统配置到产物落地3.1 获取源码稳定版优先别追最新主干Poppler 的源码托管在项目官方 Git 仓库地址在项目主页上有直接克隆下来就行git clone poppler 官方仓库地址 cd poppler这里我要多说一句不要默认检出最新的主干分支除非你想帮忙踩新 bug。Poppler 的版本迭代节奏很快主干上经常有刚合入的实验性代码对第三方依赖的兼容性还没完全打磨。生产环境建议在正式发布标签里挑一个稳定版本先执行git tag看看有哪些发布版本然后检出到你需要的那个标签例如git checkout poppler-24.08.0版本选择还有一个关键影响构建系统本身。Poppler 早期以 CMake 为主从某个大版本开始逐步加入 Meson 支持较新的版本已经停掉 CMake 维护只保留 Meson。也就是说老版本可以走 CMake 路线新版本直接上 Meson 更省心。下面两条路线我都会讲你按手里源码的版本对号入座。3.2 老版本路线CMake 配置参数逐项说明如果你的 Poppler 版本还带 CMake 支持配置命令大致如下mkdir -p build cd build cmake .. \ -G Ninja \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_INSTALL_PREFIX/mingw64 \ -DBUILD_SHARED_LIBSON \ -DENABLE_UTILSON \ -DENABLE_GLIBON \ -DENABLE_CAIROON \ -DENABLE_CPPON \ -DENABLE_LIBRARYON \ -DENABLE_OPENJPEGON \ -DENABLE_LCMSON这些参数里的核心是几个 ENABLE 开关它们直接决定编译出来的库带多少功能。ENABLE_UTILS 控制命令行工具集包括 pdftotext、pdfinfo、pdftoppm 等。如果你编译 Poppler 就是为了拿到这些工具必须打开如果只当开发库用可以关掉给安装目录瘦身。ENABLE_GLIB 和 ENABLE_CPP 分别控制 GLib 风格 C API 和 C API。绝大多数第三方程序用的是 C API也就是poppler/cpp/下面那套接口也有人用 GLib C API。建议两个都开它们只花一点编译时间但后续接不同项目的兼容面就宽多了。ENABLE_CAIRO 和 ENABLE_OPENJPEG 属于功能增强项Cairo 后端开启后才有 pdftocairo 工具也才能高质量导出 PDF 页面为 PNG 图像OpenJPEG 负责 JPEG2000 解压前面说过扫描类 PDF 全靠它。LCMS 是色彩管理做出版、设计类工具的务必开普通办公文档场景关掉可以省两个依赖。配置完成后CMake 会输出一段报告列出启用的组件花十秒钟扫一眼确认想要的都在里面。如果某个选项被标成 disabled八成是依赖没装全回头补装对应包重新配置即可。然后执行构建cmake --build . -j 6-j后面是并行任务数按 CPU 核数合理设置别盲目拉满。编译 Poppler 这种规模的库内存紧张时并行任务过多会把编译进程活活挤爆。我自己的机器用-j 6比较舒服整个过程几分钟到十几分钟。构建完成后安装cmake --install .默认装到之前指定的 CMAKE_INSTALL_PREFIX 目录。如果指定的是/mingw64可执行文件会进到 MSYS2 安装目录下的bin子目录直接在 shell 里就能调用。3.3 新版本路线Meson 配置要点新版 Poppler 用 Meson 配置更简洁命令行一眼能看懂cd poppler meson setup builddir \ -Dbuildtyperelease \ -Denable-utilstrue \ -Denable-glibtrue \ -Denable-cairotrue \ -Denable-cpptrue \ -Denable-libcurlfalseMeson 的参数命名风格和 CMake 不一样但逻辑一一对应enable-utils 对应 ENABLE_UTILSenable-glib 对应 ENABLE_GLIBenable-cairo 对应 ENABLE_CAIRO。libcurl 是用于访问远程 PDF 的选项绝大多数本地处理场景用不到关掉能少拉两个依赖。Meson 有个非常实用的特性配置完成后会输出一份详细的功能检测清单哪个库找到了、哪个库版本太老、哪个组件被强制关闭全部列得清清楚楚。如果某个你想用的功能旁边标着 NO顺着它的依赖名补装即可排查成本比 CMake 低不少。构建和安装走两条命令meson compile -C builddir meson install -C builddirMeson 后端默认是 Ninja速度上不用操心。整套流程跑完后去安装目录看一眼正常情况下会有bin和lib两个目录命令行工具和动态库各就各位。提示不管哪条构建路线编译过程中如果报错第一反应别急着去搜索引擎复制报错原文先看报错发生在哪个阶段。绝大多数问题就两类头文件找不到、链接符号找不到。前者基本是依赖没装或 pkg-config 路径不对后者基本是库版本不匹配。带着这两个预判去看报错定位速度快得多。4. 常见问题与排查技巧实录4.1 高频编译错误速查表这一节我从自己反复折腾的经历里攒了不少报错现场把出现频率最高的几个整理成表你照着排查基本能覆盖八成情况。报错现象根本原因解决方案fatal error: ft2build.h: No such file or directoryfreetype 头文件不在 include 路径安装 freetype 开发包确认 pkg-config 能查到 freetype2fontconfig/fontconfig.h: No such filefontconfig 开发包缺失安装 fontconfig重跑配置undefined reference to png_set_*一类链接错误libpng 未正确链接或版本过旧安装 libpng检查链接库顺序Could NOT find CairoCairo 开发包缺失或 pkg-config 路径错误安装 cairo把/mingw64/lib/pkgconfig加进 PKG_CONFIG_PATHCannot find -lzzlib 未被正确链接安装 zlib必要时在配置里显式指定库路径构建过程中 OOM 卡死并行任务过多内存耗尽调低-j参数或关掉部分功能再编构建系统抓到错误的编译器PATH 混入了其他 GCC 或 MSVC 的 CMake检查 PATH 顺序优先保留/mingw64/bin这里我想专门展开一下undefined reference这类链接错误。Windows 下用 MinGW 链接时库的链接顺序是敏感的被依赖的库要放在依赖它的库后面。Poppler 依赖数量多构建系统一般能自动处理顺序但老版本或者手动改过配置时就会冒出找不到符号的问题。遇到时优先查 zlib 和 libpng 这两个底层库它们被 Poppler 间接引用非常容易因为版本不匹配导致符号解析失败。另一个高频但容易被忽略的问题是换行符。Windows 上下载解压的源码包有些文件是 CRLF 换行在 MSYS2 环境里编译会触发一系列诡异的预处理错误。如果你是从 Windows 图形界面解压的源码建议先随机挑一个源文件检查编码是 CRLF 就批量转成 LF 再编译。4.2 运行期问题DLL 和字体配置编译成功只是前半程把编译好的 exe 拿到干净的 Windows 10 上运行你会遇到第二波问题典型的就是两类缺 DLL 和字体找不到。缺 DLL 很好理解。MSYS2 编译出的程序会动态链接一堆运行库包括 libgcc、libstdc 等。在 MSYS2 的 shell 里运行没问题因为 PATH 里就有这些 DLL脱离 shell 直接双击运行就会提示找不到动态链接库。解决方案是执行ldd 程序名查看它依赖哪些 DLL然后从 MSYS2 安装目录的bin文件夹里把对应文件拷贝到程序所在目录。想省事的话也可以把所有 bin DLL 一股脑拷过去就是目录会有点乱。字体找不到是更隐蔽的问题。Poppler 渲染 PDF 时需要知道系统装了哪些字体它在 Windows 上默认通过 fontconfig 做字体发现。fontconfig 依赖一个配置文件 fonts.conf 来定义字体搜索路径在 MSYS2 里没问题但把 exe 拷到别的机器后fontconfig 找不到配置轻则漏字重则所有文字变成方块。解决方法是把 MSYS2 安装目录下的etc/fonts文件夹连同程序一起拷走然后设置环境变量export FONTCONFIG_PATHE:/myapp/fonts export FONTCONFIG_FILEE:/myapp/fonts/fonts.conf同时要在 fonts.conf 里把C:/Windows/Fonts加进dir列表否则字体匹配根本覆盖不到 Windows 系统字体中文 PDF 的渲染质量会非常糟糕。注意如果处理的 PDF 里有中文强烈建议把 Poppler 配套的数据包 poppler-data 一并准备好。它提供 PDF 内部编码到 Unicode 的映射表缺了它很多中文 PDF 抽出来的文本是乱码。MSYS2 里可以安装对应的 poppler-data 包或者把数据目录通过环境变量指到正确位置。4.3 集成到 Qt 或 C 项目时的几个坑把编译好的 Poppler 接进自己的项目常见的是两种方式直接调用 C API或者用 QProcess 调用命令行工具。两种方式各有各的坑。先说 C API 方式。首先得在工程里正确指定头文件目录和库目录。假设库装在E:/popplerinclude 路径是E:/poppler/include/poppler库文件是poppler-cpp。CMake 工程里可以这样写find_path(POPPLER_INCLUDE_DIR poppler/cpp/poppler-document.h PATHS E:/poppler/include) find_library(POPPLER_CPP_LIBRARY NAMES poppler-cpp PATHS E:/poppler/lib)这里有个 MinGW 特有的细节动态库的命名通常是一对文件libpoppler-cpp.dll.a是链接时用的导入库libpoppler-cpp.dll是运行时加载的实际 DLL。构建系统找库找的是前者但最终部署要把后者放到 exe 旁边少了运行时照样起不来。用 QProcess 调命令行工具的方式更省事坑主要在参数传递和工作目录。Windows 路径带盘符和反斜杠路径里有空格时QProcess 的 setArguments 方法会自动处理引号但千万别手写拼参数字符串——引号转义在 Windows 上非常容易出错这是老程序员踩过无数次的坑。另外pdftoppm 这类工具默认把输出写到当前工作目录如果程序启动目录不是预期目录输出就会跑到奇怪的地方。稳妥做法是每次调用前用 setWorkingDirectory 明确指定输出目录。还要特别注意一点在图形界面程序里调用这些命令行工具时别在 UI 线程里同步等待。一个几百页的大 PDF 转图片可能要几十秒界面直接卡死是用户完全无法接受的。封装成异步任务或者丢到线程池里体验会好很多。我用下来最顺手的方式是 QtConcurrent 跑转换逻辑配合信号槽把结果回调到 UI 线程刷新预览。5. 成果验证和功能扩展5.1 命令行工具的完整验收流程编译安装完成后别急着收工我建议做一轮完整的功能验收几分钟的事能帮你发现很多配置阶段没暴露的问题。先准备一个测试 PDF最好同时包含文本、图片、多页以及中文内容。然后依次执行pdfinfo test.pdf pdftotext test.pdf output.txt pdftoppm -png -r 150 test.pdf page pdftocairo -png -r 150 test.pdf page_cairopdfinfo 验证元数据读取确认页数、文档版本、标题这些信息正常pdftotext 验证文本抽取打开 output.txt 检查中文有没有乱码、换行是不是合理pdftoppm 和 pdftocairo 都做页面转图测试前者走轻量后端后者走 Cairo 后端两个输出对比能直观看出渲染效果的差异。验收时有几个重点观察项中文是否乱码乱码基本指向 poppler-data 没配好图片区域是否正常解码空白块说明 openjpeg 缺失或编码特殊转出的 PNG 够不够清晰-r参数控制输出分辨率150 足够屏幕展示印刷需求可以上到 300但文件体积和耗时也会成倍增加。5.2 开发者接入一段简单的 C 示例库编译完、命令行工具验收过接下来就是真正写代码接入。如果你是 C 开发者最直接的用法是 Poppler 的 C API。下面这段代码读取 PDF 第一页的全部文本#include poppler/cpp/poppler-document.h #include poppler/cpp/poppler-page.h #include iostream int main() { auto doc poppler::document::load(E:/test.pdf); if (!doc || doc-is_locked()) { std::cerr 打开 PDF 失败或文档加密 std::endl; return 1; } std::cout 页数: doc-pages() std::endl; auto page doc-create_page(0); if (page) { std::cout page-text().to_utf8().c_str() std::endl; } return 0; }这份简短的示例里藏着好几个 Windows 特有的细节。poppler::document::load的路径参数按 UTF-8 解析Windows 下路径含中文时记得先做编码转换否则文件打不开。create_page的参数是 0 基索引第一页传 0传 1 就是第二页这个接口设计坑过不少从 1 数页的人。page-text()返回 Unicode 字符串在 Windows 控制台直接输出会是一堆问号要么把控制台代码页切到 UTF-8要么把结果写入文件再查看。编译链接命令在 MinGW 下是g -stdc17 test.cpp -I/mingw64/include/poppler -lpoppler-cpp -o test.exe如果你项目里用了 GLib 风格的 C API链接库换成-lpoppler-glib头文件路径变成poppler/glib/poppler.h基础知识体系是同一套。5.3 还能榨出哪些功能编译 Poppler 的乐趣在于当初看起来麻烦的功能开关其实都是现成模块按需打开之后能获得不少超乎看 PDF本身的能力。最实用的是用 pdftocairo 做批量转图把几十个 PDF 统一转成 PNG 或 SVG 缩略图这在文档管理系统里几乎是刚需。另一个容易被忽略的能力是 PDF 页面的抽取与合并pdfseparate 和 pdfunite 两个小工具能完成基本操作不用额外引第三方库。做全文检索系统的人一定要研究 pdftotext 的-layout参数它尽量保留原文版式输出对段落结构敏感的场景非常有用需要原始文本顺序时用-raw参数更适合做索引清洗。安全相关场景也值得挖掘。打开 NSS 支持后Poppler 能读取 PDF 的数字签名信息电子合同、票据验证类应用里常用到。虽然它不负责完整证书链校验但判断一份 PDF 带没带签名、签名是否有效足够应付大多数业务需求。渲染性能方面也提一句Splash 后端轻快适合预览场景Cairo 后端质量高适合导出印刷级图片。两条后端我都留着了实际调用时按场景切换。最后说说静态编译。如果要分发给没有 MSYS2 环境的同事使用静态链接最省心。配置时把 BUILD_SHARED_LIBS 改成 OFF链接时加-static产出的 exe 就不依赖一堆 DLL。代价是可执行文件体积从几 MB 涨到几十 MB某些依赖回调插件的功能在静态模式下不可用。我的习惯是给工具类程序做静态编译图省事给库文件做动态编译方便后续升级。编译 Poppler 这事我第一次完整跑通花了两三天最耗时间的其实不是执行构建命令的那几分钟而是反复在依赖版本、pkg-config 路径、还有 Windows 特有的环境变量问题上打转。后来我把整套流程固化成固定步骤从装环境到验收一个小时能完成再编新版或者换机器都是照方抓药。如果你在某个报错上卡住了拿上面的速查表对一下能解决八成的场景剩下两成大概率是版本差异导致的解决办法也不复杂升级或者降级对应的依赖包把构建缓存目录清掉重新配置一次。我个人还有个习惯是随手把用到的 pacman 包列表和构建参数记进项目仓库里的文档哪怕半年后再看照着就能把环境完整复现出来。