Windows下用VS2019编译Boost库:b2参数详解与排坑全程记录
发布时间:2026/10/14 6:40:07 锦皓数字建站

开头就直接进入主题。经常有人在群里问“我用VS2019写代码Boost库怎么编译啊”每次回答都要从头讲一遍bootstrap、b2参数的来龙去脉。这篇就是我当时在Windows上用VS2019从零编译Boost库的完整学习记录包括每个命令为什么这么写、每个坑是怎么踩进去的以及编译完怎么接到Visual Studio工程里、怎么验证整条链路真的通了。如果你也准备在Windows下自己编译Boost库或者在老版本VS和Boost之间反复折腾这份笔记应该能帮你省下很多看论坛和翻报错的时间。1. 动手前先想清楚你要编译谁、用什么编、编出来放哪1.1 先确认Boost版本和VS2019的工具集编号我在开始之前先确认了手头的环境Windows 10专业版装的是Visual Studio 2019C桌面开发组件完整安装了。Boost库当时选的1.84.0版本因为手头项目对这个版本测试过不想为了追新去冒险。这里有个关键信息必须先对齐VS2019对应的MSVC工具集编号是14.2Boost里面叫vc142。这个编码代表的是MSVC 14.2系列而你看到vc142这个字符串会出现在编译产物的文件名里比如libboost_filesystem-vc142-mt-x64-1_84.lib。如果你用的是VS2022工具集是14.3Boost里对应的是vc143编译参数的写法也会有差异。所以第一步不是急着下载压缩包而是先搞清楚自己用的编译器在Boost世界里叫什么名字。另外要注意操作的命令行环境。Boost的编译工装工具链对Windows很挑剔建议不要用普通cmd窗口也不要用手动设置环境变量的方式。最稳妥的是直接从开始菜单里找到“x64 Native Tools Command Prompt for VS2019”这种开发者命令提示符窗口。它里面已经帮你把cl.exe、nmake、Windows SDK的include路径全部初始化好了。如果用了普通cmdb2在探测编译器阶段大概率会报找不到cl或者找不到Windows SDK这种问题排查起来非常难受。下载Boost源码包时我选了官方网站的boost_1_84_0.zip解压到了D:\boost_1_84_0。不选带版本号有空格的路径不选中文路径这算是Windows下编译C的老规矩。解压完目录里能看到bootstrap.bat、boost头文件目录、libs目录和一堆文档。注意这里只有boost目录是头文件libs目录里面放的是各个库的源码和构建脚本不是放lib文件的地方。第一次接触的人容易在这两个名字上搞混后面配置VS时也容易把libs目录错当成库文件目录。1.2 Boost不是所有库都需要编译先圈定范围Boost库家族很大但有一个关键性质大部分Boost组件是头文件库也就是所谓header-only直接用头文件就能跑不需要链接任何lib文件。比如boost/variant、boost/optional、boost/algorithm这些你把boost目录加到include路径就行根本不用走编译流程。需要走编译的库集中在几个必须链接的组件上filesystem、system、thread、regex、date_time、serialization、chrono、program_options、locale、python等。我那次项目需要的是filesystem、system、thread和regex这四个所以在执行b2命令时用了--with-参数去指定这四组限定了范围。如果图省事不指定b2默认会把支持编译的组件全部都编一遍在一台普通机器上可能耗时两个小时还占好几个GB的临时空间。对于多数开发者来说完全没必要哪个库要用就编哪个用多少编多少这是Boost官方文档里也推荐的做法。1.3 先规划编译产物目录和命名规则编译之前先给产物想好归宿。我用的是stage模式它的意思是“编译完成后把库文件统一收集到stage/lib目录下”。还有另一种install模式它会把头文件、库文件按照boost根目录的目录结构复制到你指定的安装路径类似安装到系统目录的放法。我那次不打算影响系统环境就用stage产物在D:\boost_1_84_0\stage\lib清清楚楚。编译过程中b2会在Boost根目录下生成一个bin.v2目录里面塞满了临时对象文件、中间文件全部编译完这个目录会非常庞大。如果磁盘空间紧张可以在b2命令里用--build-dir把临时目录指到一个有足够剩余空间的盘符。我当时指到了D:\boost_build_cache同时方便编译完成后一块清理掉。2. 一次完整的编译流程实录bootstrap、b2、参数逐个拆2.1 第一步用bootstrap.bat生成b2工具在x64 Native Tools Command Prompt里先cd /d D:\boost_1_84_0然后直接执行bootstrap.bat。这个脚本做的事情是探测当前编译器环境然后用本机的cl编译一个b2.exe。b2就是Boost的构建工具它本身也是C写的所以第一步其实是“用你的编译器先把构建工具自己编出来”。如果这一步能顺利结束你会在Boost根目录下看到b2.exe同时还会生成bjam.exe老名字可以忽略。这一步可能遇到两个常见问题。第一是当前目录不对没有在Boost根目录下运行bootstrap脚本找不到源文件会报错。第二是用了普通cmd导致探测不到cl。我见过最典型的情况就是双击了bootstrap.batcmd窗口运行完一闪而过也不知道是成败。所以务必要先手动打开x64 Native Tools Command Prompt把目录切到Boost根目录再运行这个脚本这样错误信息就能留在窗口里。实际上只要不是非常老的Boost版本bootstrap这一步基本都能过真正的挑战在b2参数上。2.2 第二步b2命令参数逐个拆解bootstrap完成后我执行的编译命令是这一条先看整体长相b2 --build-dirD:\boost_build_cache toolsetmsvc-14.2 address-model64 architecturex86 threadingmulti variantrelease linkstatic runtime-linkstatic --with-filesystem --with-system --with-thread --with-regex --stagedirstage stage这条命令里的每个参数都不是摆设拆开来说toolsetmsvc-14.2告诉b2用什么编译器。VS2019对应14.2不能写错。address-model64编译64位目标。如果你的VS工程是x64平台现在基本都是这里必须64。architecturex86这里最容易误解。Boost里architecturex86不是指生成32位程序而是指目标平台属于x86体系家族配合address-model64就代表x64。如果你写architecturex86 address-model32才是32位。很多人第一次看到x86以为搞错了其实没有。threadingmulti编译多线程版本。现在任何正经程序都不会用单线程运行库所以直接写multi。variantrelease只编release版本。如果要调试断点进Boost源码就得再加debug或者改成variantrelease,debug分别编译。我当时只需要release就只编了release库文件名里就不会带gd标记gd是debug版本的标记。linkstatic生成静态库。这是关键取舍等于是把Boost功能直接编进你的exe发布时不需要带Boost的DLL。代价是exe体积变大。这个选择和后面VS工程里的运行库设置必须配套我后面会详细说。runtime-linkstatic告诉Boost你希望它链接到C/C运行库的静态版本也就是VS里那个/MT选项。它其实是描述“每个人家Boost库和你自己代码之间怎么连运行库”的约定。如果你在VS工程里用的是/MD动态运行库这里就必须改成runtime-linkshared两边不一致会导致链接阶段报一些非常难理解的外部符号错误。--with-filesystem --with-system --with-thread --with-regex只编译这四个库。没有写--without-python一类因为我用with白名单的方式直接避免了所有无关注组。--stagedirstage stage最后一个stage是动作关键词意思是收集产物到stagedir目录而--stagedirstage指定这个目录名为stage相对于Boost根目录这样产物落在D:\boost_1_84_0\stage\lib。命令写完后我加了并行参数-j 8因为我们的机器是8个逻辑核心。这个参数可以写在命令末尾b2 -j 8 --build-dirD:\boost_build_cache toolsetmsvc-14.2 address-model64 architecturex86 threadingmulti variantrelease linkstatic runtime-linkstatic --with-filesystem --with-system --with-thread --with-regex stage-j 8的意思是允许8个编译任务同时进行能显著缩短编译时间。如果不写b2默认单任务那几分钟能搞定的小范围编译也会被拖到十几分钟。但-j数字不要超过机器物理核心数否则CPU调度开销会抵消收益。2.3 编译耗时与产物形态我只编四个库机器配置一般在8并行下大约花了10分钟左右。如果你是全量编译参考耗时通常在一个小时以上。期间屏幕上会不断滚动每个源文件的编译进度出现一堆file、bin.v2的路径信息。看到最后出现...failed updating N targets...之类的东西才是有问题的地方普通的warning可以暂时忽略。编译完成后进入D:\boost_1_84_0\stage\lib能看到类似这样的文件libboost_filesystem-vc142-mt-x64-1_84.lib libboost_system-vc142-mt-x64-1_84.lib libboost_thread-vc142-mt-x64-1_84.lib libboost_regex-vc142-mt-x64-1_84.lib我选的是linkstatic所以文件都以lib开头。Boost的文件命名规则相当于一份编码说明书拆解libboost_filesystem-vc142-mt-x64-1_84.liblib前缀表示静态库boost_filesystem是组件名vc142是VS2019工具集mt是多线程x64是64位目标1_84是Boost版本号1.84.0没有任何gd标记说明这是release版。动态库的命名风格就完全不同。如果你把linkstatic换成linkshared产物会变成boost_filesystem-vc142-mt-x64-1_84.dll和boost_filesystem-vc142-mt-x64-1_84.lib后者是导入库名字里没有lib前缀同时还会附带.exp导出文件。所以看到一个boost的lib文件名第一件事就是看有没有lib开头这决定了它是静态库还是动态库的导入库后面配置错了通常就是在这个地方翻了车。3. 编译踩坑全记录三个坑的完整排查链路3.1 坑一bootstrap.bat运行后一闪而过看不到任何输出这个坑我是在另一台机器上踩的不是我自己那台。同事说运行bootstrap.bat后黑窗口一闪就消失了也不确定成没成功。我过去一看明显是双击了bootstrap.bat。在Windows上双击bat文件如果脚本没有pause窗口运行完就会自动关闭报错信息也就一起消失了。这个现象其实验证了前面说的要在命令行工具里执行让错误输出停留在窗口里。排查链路是这样的先打开x64 Native Tools Command Prompt切换到Boost根目录运行bootstrap.bat。这时候窗口里会显示脚本正在生成b2.exe的过程。如果这里弹出cl: 未找到或者Cannot find cl.exe说明当前的命令行环境里没有编译器。解决方式是确认自己开的是“x64 Native Tools Command Prompt for VS2019”而不是普通cmd或者如果有Visual Studio安装器的话重新修复一下“使用C的桌面开发”组件。如果脚本本身卡住不动更要留意是不是杀毒软件正在拦截b2写入可执行文件。3.2 坑二编译到中途报fatal error C1083无法打开包含文件这个坑也很有代表性。编译Boost的filesystem组件时日志突然出现类似fatal error C1083: Cannot open include file: sys/stat.h: No such file or directory的报错。当时心里的第一反应是Boost源码缺文件但后来又一想Boost源码里不会依赖libc的头文件这个sys/stat.h明显是Windows SDK里的头文件。问题不在Boost在于b2根本没有找到Windows SDK的include路径。排查链路一步步走先确认命令行窗口是x64 Native Tools Command Prompt这个环境应该会设置好INCLUDE环境变量。然后在同一个窗口里执行echo %INCLUDE%看里面是不是包含C:\Program Files (x86)\Windows Kits\10\Include\...这类路径。如果输出为空说明这个窗口根本没有继承VS的环境变量。为什么环境变量会丢常见原因是当时开了多个命令行窗口顺手在一个旧窗口里就开始执行b2而旧窗口是在VS安装或修复之前创建的INCLUDE是空的。解决方式是关掉所有旧命令行窗口从开始菜单重新启动x64 Native Tools Command Prompt。另一个隐蔽原因是在普通cmd窗口里先手动执行了vcvarsall.bat x64然后觉得环境好了但Boost的b2在某些情况下对INCLUDE的探测有时序依赖如果某个给b2的过程传入的环境变量被空格或者引号弄乱了也会出现找不到头文件的情况。最稳妥的做法始终是直接用VS自带命令行工具不要让手写环境变量出现在错误报告里。3.3 坑三VS工程链接时找不到Boost符号库名对不上这个坑是编译完成之后才出现的也是新手最容易卡住的地方。我把stage\lib路径加到了VS2019的链接器附加库目录里编译阶段一切正常链接时却报了一堆LNK1104: 无法打开文件libboost_filesystem-vc142-mt-x64-1_80.lib或者无法解析的外部符号。看到这个报错第一反应是路径没配好但我重新检查发现路径是对的。再仔细看它找的是1_80我编译的是1_84。原来VS工程里用了Boost的自动链接机制Boost头文件里有boost/config/auto_link.hpp它会在没有显式指定BOOST_LIB_PREFIX等宏的情况下根据编译器版本和配置自动生成一个库文件名并告诉链接器去链接。这个文件名的格式依赖BOOST_LIB_VERSION宏这个宏来自Boost版本头文件理论上不会错但当时项目里同时引用了两个不同版本的Boost路径include目录顺序导致boost/version.hpp被先解析成了1.80版本。于是链接器拿着1.80的库名去找文件自然找不到。排查链路最后定位到工程的附加包含目录最上面的一个boost路径指向老版本b2编译的新版本排到了后面。预处理器永远先解析排在前面的include路径所以版本被锁定在了旧版。把新版本路径移到最上层重新编译链接报错消失。这个坑的教训是项目里如果存在多份Boost副本一定检查include目录的优先顺序同时可以在VS的“C/C - 预处理器 - 预处理器定义”里显式加一个BOOST_LIB_VERSION检查或者在auto_link.hpp处打断点看实际用到的版本头文件是哪一份。如果不想依赖自动链接机制也可以在自己的工程里定义BOOST_ALL_NO_LIB然后在附加依赖项中手动写链接的库名这样错位的可能性就降到最低。4. 编译完不等于结束VS2019工程里的配置实操4.1 配置头文件路径和库目录的位置编译完Boost库接下来要把整个链路接到VS2019工程里。这一步很多人以为只是填两个路径实际操作中有几个细节值得注意。打开项目属性页在“C/C - 常规 - 附加包含目录”填入D:\boost_1_84_0。这里必须指出不是填D:\boost_1_84_0\boost而是填Boost根目录。原因是Boost源码里所有头文件引用都是以#include boost/filesystem.hpp的形式写的这个boost前缀就是根目录下的boost文件夹。如果你只把boost文件夹本身加到include路径反而会让#include boost/...查找失败因为编译器会在你给的路径下找boost/boost/filesystem.hpp。这是个非常容易手滑的点。然后打开“链接器 - 常规 - 附加库目录”填D:\boost_1_84_0\stage\lib这是编译产物所在目录。如果你当时用了install模式库文件在自定义目录里填那个就行。4.2 打开自动链接还是手动链接看你的工程情况Boost有一个自动链接机制大部分组件在include头文件后会让链接器自己去找对应的库文件不需要你在“链接器 - 输入 - 附加依赖项”里逐个添加*.lib。这个机制对release和debug、32位和64位会自动匹配不同的文件名。听着很方便但在多配置工程里其实容易惹麻烦比如前面说的多版本Boost路径错位问题以及debug和release库名不匹配的问题。我个人的做法是如果编译的是动态库版本必须在“C/C - 预处理器 - 预处理器定义”中加入BOOST_ALL_DYN_LINK。这个宏告诉Boost“当前工程使用Boost动态库”头文件会根据这个宏去链接导入库而不是静态库。如果忘加哪怕你在附加库目录里放了DLL的导入库链接器仍会抱怨找不到libboost_...开头的静态库文件。如果选择静态库我建议要么自己维护附加依赖项要么至少确认自动链接找的库名和你实际编译出来的文件名一致。调试阶段更稳妥的做法是定义一个BOOST_ALL_NO_LIB禁用自动链接然后在“链接器 - 输入 - 附加依赖项”里手工写明用到的几个库名。这样虽然每次新增组件时都要手动加一次但至少你知道链接器在找谁、为什么用这个文件出了问题容易定位。一旦工程的配置项多了这种显式控制反而省心。4.3 运行库设置必须和Boost编译参数对齐这里有一个非常容易踩的配置配对问题。你在VS工程里的“C/C - 代码生成 - 运行库”选项有两个常用形态/MT多线程静态运行库和/MD多线程DLL运行库。这个选项必须和你编译Boost时用的runtime-link参数一致。我当时编译Boost时用了runtime-linkstatic所以VS工程里应该选/MTRelease下是/MTDebug下是/MTd。如果你在VS里用的是/MD但Boost是runtime-linkstatic链接阶段会抛出类似“无法解析的外部符号 _imp...”、“operator new 已经在 xxx.lib 中定义”这类符号冲突。这类报错非常像代码写错了实际上纯粹是运行库选择不一致引发的。反过来如果Boost编译全部用了linkshared runtime-linksharedVS里就对应/MD。一个工程从开始就要定下这个组合中途不要随意改动。你的发布包策略也受它影响/MT 静态Boost库exe不依赖任何Boost DLL/MD 动态Boost库发布时要同时带上Boost的DLL文件。如果是做一个需要下发给别人绿色运行的演示程序前者更省事。4.4 验证整条链路通没通写个小测试程序配置完不要急着写业务代码先用一个小程序验证编译和链接都通了。我当时写了这样一个测试#include boost/filesystem.hpp #include boost/thread.hpp #include iostream int main() { boost::filesystem::path p(C:/Windows); std::cout exists: boost::filesystem::exists(p) std::endl; boost::thread::id id boost::this_thread::get_id(); std::cout thread id: id std::endl; // 手动移除了尖括号,避免触发转义 return 0; }这段代码同时用到了filesystem和thread两个组件如果链接配置有问题编译阶段顺利通过链接时就会报错。编译和运行都正常后基本可以确定头文件路径、库目录和运行库配置三条线已经交圈。注意观察输出窗口有没有DLL加载失败的弹窗这也验证了静态库确实编进去了没有运行时才对Boost DLL的需求。5. 写给准备在Windows上编译Boost的人几条实在建议5.1 版本选择别盲目追新先看VS版本配合Boost版本更新很快但我不建议每一个新版本都立刻上生产。重点要看它和VS2019工具集的配合情况。Boost新版本一般会保留对前几个MSVC版本的兼容但偶尔也会出现新版本默认要求更高Windows SDK版本的情况。如果你的VS2019没装最新SDK编译时会遇到一些莫名其妙的配置错误。最稳妥的做法是找一个当前项目验证过、论坛反馈也稳定的版本尽量避开刚发布一两周的大版本。另外Boost版号在文件名里的编码是下划线格式比如1.84.0对应1_841.80.0对应1_80搜索资料或手动填库名时要注意这个编码规则不要写成1_84_0当成三段去找文件。5.2 静态库和动态库的取舍要在项目一开始就定好Windows下Boost编译时最核心的选型其实是静态还是动态。静态库在编译阶段全部编进exe发布机器上干干净净不用拷DLL缺点是exe体积会大不少而且如果多个程序都静态链接了对应Boost组件内存中同一份代码会有多份副本。动态库的好处是多个程序可以共享同一份DLL缺点是发布时容易漏掉DLL运行时环境稍微一乱程序就起不来了。我个人的经验是如果是给自己或者小团队做内部工具、演示Demo静态库加/MT最省心。如果是做成大型服务端程序部署环境可控、有统一安装脚本动态库加/MD更合适。实际开发中服务端组件之间用动态库也不容易遇到符号冲突。更重要的是一旦选定组合工程里的“运行库”选项就不要动不动切换否则每次切换都要把Boost重新编译一套对应的库别问我怎么知道的。5.3 编译过程的临时目录和并行度记住这几点b2的临时目录bin.v2非常吃空间编译几十个组件时磁盘上会有好几个GB的中间文件。建议把--build-dir单独指到一个空间充足的盘符编译完如果确定不再重新编译直接删掉整个临时目录就行不会影响stage\lib里的成果。并行度-j按核心数写不要盲目填32。开太多任务时每个编译进程会争抢内存和磁盘IO耗时反而可能上升机器还会卡到鼠标都动不了。另外编译过程中如果杀毒软件频繁扫描编译器进程和临时目录可能让编译时间翻倍临时把Boost解压目录和临时目录加入杀毒白名单能省不少时间。5.4 多版本Boost并存时include路径顺序就是一切如果你电脑上同时有多个Boost版本老系统项目里很常见一定要时刻检查VS工程的附加包含目录顺序排在上面的路径会优先被预处理器命中。我当时就是因为老版本路径排前面导致链接器去找旧库名。解决方式很简单把新版本目录移到最上层或者在项目里只用一份Boost另一份的include路径彻底移除。不要觉得多放一个路径没影响C预处理器的查找顺序从来都是从上到下一击命中路径顺序直接决定了编译用的版本。5.5 把编译命令保存成脚本别每次手敲编译Boost的参数又多又长而且不同项目可能要用不同组合。建议把编译命令写进一个bat脚本放在Boost解压目录旁边。比如针对当前项目的脚本就叫build_boost_1_84_static_mt.bat内容就是一条完整的b2命令。下次需要重编或者给另一台机器配环境直接双击再改改参数就行。我后来给新电脑装环境的时候就是这样脚本一跑十分钟后拿库文件走人省去逐条回忆参数的时间。我自己实际编译过几次之后总结下来Windows上编译Boost的整个流程真正繁琐的地方不在命令本身而在于各种组合条件必须自洽编译器版本要和toolset对应目标位数要和VS工程对应静态动态选择要和运行库设置对应debug/release要和工程配置对应库目录和include路径顺序也要对应。只要这些对应关系不打架一次编译通常很顺利。希望这份记录能让你少走几步弯路。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。