Windows源码编译LLVM:VS与MinGW双路线实战指南

发布时间:2026/10/19 5:07:20
Windows源码编译LLVM:VS与MinGW双路线实战指南 先交代一个前提这篇文章里所有操作我都用“源码目录”指代LLVM的检出目录“构建目录”指代CMake生成的编译目录避免路径差异干扰。我实测过Windows 10/11两代的x64环境VS 2019和2022都跑过MinGW用的也是当前主流的w64线程模型版本。下面这些经验基本都来自实际编译时的记录踩过的坑也会一并写清楚。1. 为什么要在Windows上编译LLVM网上关于LLVM的讨论很多默认大家用的都是Linux。但实际工作中总有一些场景必须在Windows下编译比如给某个跨平台项目做代码分析工具链、在公司内网没法直接拉官方release包、或者你想给LLVM本身打补丁调试。我自己第一次编译LLVM是在做某跨平台系统的性能分析模块时需要用Clang的静态分析功能但内网环境和目标平台都是Windows只能硬着头皮在Windows上折腾工具链。Windows下编译LLVM本质上就是两条路用Visual Studio的MSVC编译器或者用MinGW-w64的GCC编译器。前者主要产出一套完整的.sln解决方案方便在IDE里边改代码边编译后者走的是Classic Makefile或Ninja风格更像在Linux上操作。两条路都能编译出可用的llvm、clang、lld但细节差异非常大选错方向会浪费很多时间。很多人问为什么不直接下载官方预编译包。答案是能用官方包当然最省事但如果你要改LLVM源码、调试pass、或者定制clang工具链就必须自己编译。而且Windows上编译LLVM的门槛并没那么高把CMake参数理清楚之后成功率甚至比想象中高。这篇就是想把我在配置、编译、排错过程中沉淀下来的东西捋一遍给准备动手的人一份可参照的路线。1.1 什么人需要自己编译LLVM需要自己动手的场景大致有三类。第一类是给LLVM上的子项目做定制比如要给Clang加自定义warning、给后端target加指令支持这些都必须从源码编译。第二类是性能敏感场景官方release包的build type通常是Release但如果你要调试编译过程本身需要Debug或RelWithDebInfo版本。第三类则是公司内网的离线构建既没有外网下载条件又要保证工具链可控源码编译就成为唯一选择。这三种场景我都遇过。最痛苦的不是编译本身而是Windows上CMake生成器和工具链之间的配合。VS生成器下CMake会把平台信息交给MSBuild处理不太需要操心环境变量MinGW模式下你要是把编译器路径配错了或者用了不匹配的make程序会在configure阶段就报各种莫名其妙的“Unable to find”错误。所以这篇文章会重点把这两种模式的配置差异讲清楚。1.2 VS和MinGW两条路线怎么选先说结论如果你主要工作环境是Visual Studio打算在IDE里开发、调试LLVM选VS生成器也就是用MSVC编译。这有个很大的优势LLVM官方把MSVC作为Windows上的一等公民相关构建脚本都维护得比较完整clang-cl的配置也是默认考虑过的。如果你更习惯Linux那套命令行习惯或者你编译出来的工具链要配合GCC风格使用选MinGW更顺手。但要注意一个关键点MinGW路线下编译器是gcc/g链接器是GNU ld而CMake里的生成器可以是“MinGW Makefiles”也可以是“Ninja”。很多人把生成器和编译器混淆。实际组合上我推荐MinGW搭配Ninja因为Ninja的并行度高编译速度明显快过原来的mingw32-make而且增量构建稳定很多。VS路线下则不需要Ninja直接用MSBuild。两条路线的资源消耗也不同。实测下来全套LLVMClanglld编译VS模式生成的中间文件会多一截整个构建目录轻松占掉25GB到30GBMinGWRelease模式大概18GB左右。内存上如果只开单项目比如LLVM核心8GB内存够用但一旦开了clang建议至少16GB否则容易在链接阶段被内存撑爆。2. 动手前的准备工具链和依赖清单编译LLVM最怕的不是编译过程而是环境不干净。这一步我吃过亏一开始只装了VS没装“单个组件”里的C工具集CMake configure直接报找不到MSVC工具链排查了很久才发现是组件缺失。所以动手前先把环境列个清单逐项过一遍能省很多后续折腾。2.1 Visual Studio安装时容易被忽略的组件安装VS时大家通常只勾了“使用C的桌面开发”这个工作负载。但对LLVM来说有些头文件和库的依赖是隐含的。建议检查一下这几个选项Windows 10/11 SDK默认会装但注意如果只装了旧版本clang编译Windows头文件时可能出问题。MSVC v143或v142生成工具这是核心编译器不装等于白搭。C CMake tools for Windows可以帮VS里的CMake项目省点事但这里不是必须因为我们用命令行cmake。Git建议装上后面拉源码用。安装好之后打开“开发者命令提示符”或者任何终端输入cl命令能识别就说明MSVC环境可用了。注意普通终端是找不到cl的必须用VS提供的“Developer PowerShell”或“x64 Native Tools命令提示符”进入。2.2 MinGW-w64的选择与配置MinGW有两个大版本一个老牌的MinGW-w64 GCC系列另一个是WinLibs构建版。我建议用WinLibs或者从合适渠道下载的w64版gcc因为版本较新还带了gdb等工具。务必选64位版本LLVM全量编译用32位工具链你会非常难受。装好后按gcc --version能输出版本号即可。之后要把MinGW的bin目录加到系统PATH里比如C:\mingw64\bin。这里有个坑如果PATH里同时存在多个gccCMake会选出第一个可能导致后面生成器探测不一致。我踩过这个坑所以建议把MinGW的bin路径放在PATH靠前位置或者干脆在CMake配置时手动指定编译器路径。2.3 CMake、Python、Ninja的版本要求LLVM对CMake版本有最低要求大体上是3.20以上。建议直接用最新的3.27或3.28旧版本在某些新配置项上会直接warning甚至报错。Python必须装3.6以上因为LLVM构建脚本里大量使用了Python做代码生成我实测过Python 3.11、3.12都能正常工作。Ninja单独下载一个最新release就可以把ninja.exe扔进PATH即可无需安装。这里顺带解释一下为什么LLVM需要Pythonllvm-tablegen等工具是基于C实现的但一些测试脚本和lit测试框架是Python写的另外clang的一些编译选项生成脚本也调用了Python。没有Pythonconfigure阶段过了但构建阶段随时可能挂。2.4 磁盘、内存和CPU资源评估LLVM全量编译对资源的要求超过很多人预期。最低建议是16GB内存、30GB可用磁盘、4核以上CPU。我只编译LLVM核心和Clang时Release构建耗时在8核机器上大约40到60分钟如果全开所有target时间会翻倍。如果内存只有8GB也有办法控制并发数、关闭CCache、只编核心target。但这会牺牲很大效率。更实际的建议是能让机器跑Linux虚拟机就不要在Windows上折腾但如果项目硬要求在Windows平台那至少把内存加到16GB。3. CMake配置的完整拆解这一步是整个编译过程的灵魂。LLVM的构建系统非常灵活但也因为灵活很多人容易被一堆-D参数吓住。其实只要理解两件事就行生成器选谁、项目开哪些。剩下就是围绕这两个主决策去补充参数。3.1 获取源码的正确姿势源码获取我推荐用git克隆官方仓库的release分支而不是直接下压缩包。因为LLVM后续往往会切tag、更新submodulegit管理起来方便很多。命令很简单git clone --depth1 -b llvmorg-17.0.6 https://github.com/llvm/llvm-project.git注意--depth1能省大量下载时间但如果你打算长期调试历史版本最好别加这个参数而是完整克隆。LLVM仓库里包含了llvm、clang、lld、libcxx等所有官方子项目都在同一个仓库内不需要单独下载。3.2 核心配置项逐个说明CMake配置项很多但真正影响成败的就这几个CMAKE_BUILD_TYPERelease、Debug、RelWithDebInfo、MinSizeRel。如果只是要工具链用选Release要调试LLVM内部逻辑选RelWithDebInfo或Debug。注意Debug版本体积巨大且慢初学者慎选。LLVM_ENABLE_PROJECTS你需要的子项目用分号分隔。我一般写clang;lld有需要再加clang-tools-extra。这个参数一定要在第一次configure就写对因为LLVM要求在配置阶段就决定要构建哪个子项目后面改可能引发全量重建。LLVM_TARGETS_TO_BUILD默认会构建所有支持的后端target比如X86、ARM、AArch64、RISCV等。很多人没意识到这是个巨大的时间黑洞。如果你只是在x86机器上做常规开发写X86就足够能省掉近一半编译时间。需要交叉编译再加对应后端。LLVM_ENABLE_ASSERTIONS默认跟build type走Release下是OFF。做开发调试建议显式打开但要注意会降低运行时性能。CMAKE_INSTALL_PREFIX最终安装路径建议单独指定比如D:\LLVM-17这样ninja install出来干干净净。还有几个值得注意的次要点LLVM_USE_LINKER可指定使用lld作为链接器能显著加快链接LLVM_CCACHE_BUILD建议打开多次增量构建会省时间CLANG_ENABLE_STATIC_ANALYZER一般默认开不消耗额外资源。3.3 使用VS生成器的配置示例VS模式的配置命令长这样。注意必须在“开发者PowerShell”或“x64 Native Tools命令提示符”里运行cmake -G Visual Studio 17 2022 -A x64 -Thostx64 -DCMAKE_BUILD_TYPERelease -DLLVM_ENABLE_PROJECTSclang;lld -DLLVM_TARGETS_TO_BUILDX86 -DLLVM_ENABLE_ASSERTIONSOFF -DCMAKE_INSTALL_PREFIXD:\LLVM-17 ../llvm-project/llvm-T hostx64表示宿主工具用64位否则默认可能是32位编译大项目容易撑爆进程。-A x64指定目标架构。配置完成后CMake会在构建目录里生成一个LLVM.sln之后用VS打开选好配置和平台就能Build。当然也可以走命令行用msbuild或者cmake --build。VS模式最大的好处是IDE集成舒服断点调试源码时VS的Source Link和符号处理都很成熟。但坏处是如果代码里改了CMakeLists用VS重新配置时偶尔会出现缓存不刷新的情况需要手动删除CMakeCache再重新配置。3.4 使用MinGW生成器的配置示例MinGW模式我推荐Ninja生成器配置命令如下cmake -G Ninja -DCMAKE_BUILD_TYPERelease -DCMAKE_C_COMPILERgcc -DCMAKE_CXX_COMPILERg -DLLVM_ENABLE_PROJECTSclang;lld -DLLVM_TARGETS_TO_BUILDX86 -DLLVM_ENABLE_ASSERTIONSOFF -DCMAKE_INSTALL_PREFIXD:\LLVM-17-mingw ../llvm-project/llvm这里-G Ninja指定生成器CMAKE_C_COMPILER和CMAKE_CXX_COMPILER手动指定编译器路径防止CMake用了环境变量里其它gcc。执行完cmake --build . -j 8就能开编。有个地方要特别提醒Ninja模式下不要混用cmake和系统make。很多人配好后忘了装ninja就顺手把-G改成MinGW Makefiles再用mingw32-make去编。这也能成但遇到增量构建时比较挑TMP环境变量偶尔会出现resume时重新编译大量文件的情况。所以Ninja还是优先选择。3.5 两种生成器的本质区别这两种生成器的区别值得单独说清楚。VS生成器是多配置的它会把编译、链接命令打包到.sln里你可以在同一个构建目录里反复切换Debug/Release而不重新配置CMake。MinGW/Ninja生成器是单配置的它在configure阶段就定死了build type切换Release到Debug需要重新配置一个单独的目录。也就是说VS模式下你惯用的“改个选项就重新编译”在MinGW模式下行不通。我实际工作里会准备两个目录一个build-release供日常用一个build-debug供调试用这样互不干扰。磁盘空间足够的话非常推荐这种双目录方案。4. 构建实战与验证配置完成之后就是漫长的编译过程。我见过不少人在这一步因为并发太高或磁盘空间不足翻车所以这部分把构建过程中的实操要点和验证方式一并讲透。4.1 VS方式构建与增量编译VS模式下你可以直接在VS里按F5或CtrlB构建也可以命令行执行。命令行下建议这样cmake --build . --config Release --parallel 8--parallel 8对应CPU核数。如果编译过程中你改了源码再跑一次同样的命令MSBuild只编译变更过的文件这就是增量编译。不过要注意如果你改了CMakeLists.txt或者llvm-config.h.cmake这类配置文件MSBuild会触发重新生成CMake相关文件并重新编译一大批文件这是正常现象。VS模式下还有个隐藏坑默认的字符集和编译选项与LLVM的脚本可能产生冲突。特别是某些老版本LLVM在MSVC下编译llvm-tblgen时会报C4715等warning一般不影响结果但建议在CMake里加-DLLVM_ENABLE_WARNINGSOFF来减少噪音。4.2 MinGW方式构建MinGW Ninja的构建命令很干净cmake --build . --parallel 8ninja会自动读取构建目录里的配置。第一次编译LLVMClang时看到大量编译日志滚动是正常的。建议把输出重定向到日志文件比如cmake --build . --parallel 8 21 | tee build.log万一中途报错可以在日志里搜error:关键词定位问题避免一遍遍翻终端。Ninja模式下链接阶段的内存压力比VS模式更明显。我遇到过一次ld进程直接崩溃就是并发太高导致的。解决办法是降低并行度或者给链接器指定-Wl,--threads参数减少内存占用。更稳妥的是在CMake配置时加一句-DLLVM_USE_LINKERgold用gold链接器比默认的bfd链接器占用内存小不少。4.3 产物验证用法检查clang和llc编译完成或者中途怎么验证产物可用其实不用等装完直接在构建目录里就能找到二进制。我一般先验证三个东西bin\clang.exe --version确认clang能运行、版本号正确、target是x86_64-pc-windows-msvc或gnu。bin\llc.exe --version注册的后端target列表里是否包含x86。bin\llvm-config.exe --components看核心库和组件是否齐全。写一个最简单的C文件用编译出的clang编译成目标文件#include stdio.h int main() { printf(hello llvm\n); return 0; }然后执行bin\clang.exe -c hello.c -o hello.o如果能正常生成hello.o就说明编译器主干流程是通的。想更进一步的话可以链接成可执行文件MinGW模式下用它编译的exe体积会偏大这是正常的GCC的默认启动文件和静态链接风格决定了这一点。5. 常见问题与排查技巧实录编译LLVM最让人头疼的往往是问题五花八门而且很多错误信息在网上搜不到准确答案。这一节我把几个真实撞过墙的问题整理出来按概率排序。5.1 路径与编码空格、中文目录这个问题几乎必躺。CMake配置阶段如果源码根目录或构建目录包含空格、中文或者特殊符号Ninja和MSBuild都会出诡异错误。比如D:\Program Files\llvm-projectNinja在构建时会报“ninja: error: expected ”之类的信息一开始根本想不到是路径问题。MSVC编译器也会对非ASCII路径产生异常行为。解决方案非常简单所有的目录都用纯英文路径中间不要有空格。最稳的是建一个像D:\llvm-src、D:\llvm-build这样的短路径从头到尾避开麻烦。另外Windows系统用户名如果是中文默认的Temp路径可能也带着中文这时候先手动设置环境变量TMP和TEMP到英文目录再启动编译能避免很多奇奇怪怪的报错。5.2 VS编译内存耗尽用VS构建时候最经典的是链接阶段报LNK1102: invalid object file或者fatal error LNK1102: 无法打开文件这种多半是内存不足。MSVC的link.exe在链接clang和lld这种大型可执行文件时峰值内存可以到4GB甚至更高。并行链接时如果开了8路内存很容易冲破16GB。遇到LNK1102先不要怀疑代码问题。我的解决办法是降低/maxcpucount或者在VS里一次只构建一个目标不要选择“Build Solution”而是单独Build clang这个target。还有一个更巧的办法先用build-bin顺序编几个小工具把磁盘缓存热起来再编大目标内存压力会小一些。5.3 MinGW链接错误MinGW模式下的经典错误是undefined reference to_imp...一般出现在链接阶段调用Windows系统库的时候。这通常是编译器路径配置有问题导致gcc链接时没有找到正确的libkernel32.a等导入库。排除方法很简单执行gcc -v看下它的library search路径是否指向你的mingw64目录。另一个常见错误是direct2d相关的Undefined symbols这通常是因为打了老版本SDK头文件。解决办法是确认Windows SDK版本并让clang或gcc附带-D_WIN32_WINNT0x0A00这类宏定义保证头文件识别对系统版本。5.4 构建太慢怎么办构建慢不是错误但比错误更折磨人。想提速第一件事是用ccache或者sccache。Windows上sccache配合MSVC非常好用第二次全量构建能减少一半时间。我配置过一次sccache重编LLVMClang时编译时间从45分钟压缩到20分钟左右效果显著。其次检查是不是把不必要的东西编进来了。如果LLVM_TARGETS_TO_BUILD是ALL那你正在为几十种架构浪费时间。我见过一个同事为了写一个x86后端pass把ARM、MIPS、RISCV全编了磁盘多占8GB时间多花30分钟完全没有必要。最后如果你的机器有多块盘把源码放在SSD上把构建目录放在另一块SSD或机械盘上实际体验差别能感觉得出来。构建目录的随机读写量非常大机械盘会让编译时间显著拉长。6. 编译之后还能做点什么很多人以为编译完就结束了其实真正的价值在产物怎么用。我编译LLVM不只是为了跑clang更多是为了两个目的一是给某个图像处理Demo做自动向量化实验二是基于LLVM写一个简单的自定义Pass做IR变换。拿到自编译的clang后除了日常编译代码我最推荐做的事是跑一遍llvm-lit -sv test/里的简单测试集。编译出来的构建目录中自带lit和测试配置直接在构建目录里运行ninja check-llvm能跑几千个回归测试。这不仅能验证工具链正确性也是熟悉LLVM测试体系的第一步。对于想做二次开发的人建议先读一下llvm/lib/Passes/PassBuilder.cpp和llvm/include/llvm/IR/PassManager.h这是LLVM新的Pass管理框架核心也是后续写Pass必用的入口。Windows下调试时VS的调试器能正常识别LLVM的源代码符号比在很多IDE里方便得多。MinGW模式下想要调试可以生成DWARF调试信息用gdb和VSCode配合也能跑但体验上确实比VS差一点。我个人在实际操作里的体会是Windows环境编译LLVM真正的门槛不在工具链本身而在“CMake生成器和工具链的匹配关系”以及“会不会正确控制构建范围”这两件事上。这些参数在官方文档里都有但没人告诉你组合顺序和坑。把环境理顺之后LLVM的构建流程其实非常机械完全可以自动化脚本化后面再编译别的版本就只是改几个版本号的问题。最后再分享一个小技巧把从configure到build的整条命令存成批处理脚本每次改动只用改版本号和目标名这样即使半年后再来一次也不会因为陌生而手忙脚乱。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询