简介:一套面向Windows 64位平台的Boost 1.78动态库编译包,采用MinGW 7.3.0工具链生成,同时打包Debug与Release两种版本,专门服务使用Qt Creator的C++开发者。压缩包文件总量超过一万五千个,其中包含一万四千五百余个hpp头文件、二百六十余个ipp实现文件,另有一百六十余个cmake配置、一百四十余个h头文件、七十个静态导入库与六十六个动态链接库,覆盖指针、线程、正则、序列化、日志等常见Boost模块。整包约五十一点二一兆字节,已有二百六十人学习使用。配置到Qt Creator的工程文件或构建路径后即可直接调用,免于手动编译;Debug版保留调试信息,Release版针对性能与体积优化,适配开发到上线的完整流程。该工具链版本与Qt Creator内置编译器一致,可有效避免版本不匹配带来的链接错误;整个包内文件组织清晰,头文件、库文件分类明确,便于按需配置和引用。
1. Boost 1.78 + minGW730 64 位动态库:一份能直接用的预编译 C++ 依赖
在 Windows 上用 MinGW-w64 7.3.0 写 C++,Boost 库的编译问题几乎是每个人都会撞上的墙:自己下源码、跑 bootstrap、再等 b2 编译,少说半小时起步,工具链版本不对还会收获一堆 undefined reference。这个资源包 Boost1.78_minGW730_64位_动态_Debug和Release 直接给出了 Boost 1.78 的预编译产物,针对 minGW730(GCC 7.3.0,64 位)工具链,同时包含 Debug 和 Release 两套动态库。拿到手不需要自己编译,把 include 和 lib 路径指给编译器,按构建类型选库就能跑。适合正在用 MinGW-w64 7.3.0 写桌面程序的 C++ 开发者,也适合不想在 Boost 编译上耗时间的从业者。下面从库命名和 ABI 匹配讲起,一直拆到 CMake 集成和运行时避坑。
2. 先看懂这份预编译库:命名规则、ABI 匹配与动态链接选型
2.1 解压后的文件结构:DLL、导入库和头文件的分工
这种预编译 Boost 包的结构通常很规整,拿到手先别急着抄路径,花两分钟看清文件分布,后面能省不少事。典型目录是这样:
include/boost/... # 所有头文件 lib/libboost_*-mgw73-mt-*.dll # 运行时 DLL lib/libboost_*-mgw73-mt-*.dll.a # MinGW 导入库,链接时用MinGW 使用的导入库不是 MSVC 的.lib,而是.dll.a。g++ 链接时从.dll.a里找符号,程序运行时才加载.dll。所以链接阶段和运行阶段依赖的文件后缀不一样,漏掉任何一个都会出问题。比如libboost_filesystem-mgw73-mt-x64-1_78.dll.a是对应libboost_filesystem-mgw73-mt-x64-1_78.dll的导入库,链接命令里写-lboost_filesystem-mgw73-mt-x64-1_78,程序跑起来时找的是前者名字去掉lib前缀、换.dll后缀的那个文件。
Boost 预编译库的命名不是随便起的,每个字段都有意义。以 Release 版为例:
| 文件名字段 | 含义 |
|---|---|
lib | MinGW 统一的前缀 |
boost_filesystem | Boost 模块名 |
mgw73 | 工具链是 MinGW-w64 GCC 7.3.0 |
mt | 多线程运行时版本 |
x64 | 64 位目标 |
1_78 | Boost 版本号 1.78 |
.dll.a | 导入库,对应同名.dll |
Debug 版会在mt后多一个d,比如libboost_filesystem-mgw73-mt-d-x64-1_78.dll.a。这个d就是 debug 的标记,链接时选错,后面第四章会专门讲后果。还有一点很重要:MSVC 环境下 Boost 头文件有 auto-link 机制,会自动选择对应的 lib,但 MinGW 没有这个待遇,所有库都得在编译命令里手动指定,这也是命名规则必须看懂的原因之一。
2.2 为什么必须绑定 minGW730:GCC 的 C++ ABI 不是跨版本通用的
很多人会问:Boost 是标准 C++ 库,换个编译器版本应该也能用吧?答案是不能,尤其是 C++ 的 ABI 会变。MinGW-w64 的 GCC 从 7.x 升级到 8.x,libstdc++ 的std::string实现、异常处理模型、模板实例化的符号修饰都可能变化。GCC 7.3 编出来的 Boost 动态库,你拿 GCC 8.1 的 g++ 去链接,轻则告警,重则出现undefined reference to std::__cxx11::basic_string这类符号找不到的问题。所以这个包标注了 minGW730,你就老老实实用 7.3.0 的编译器去编你的工程。
更具体地说,GCC 5.1 之后引入了 C++11 ABI,默认启用新的std::string布局。GCC 7.3 的_GLIBCXX_USE_CXX11_ABI默认是 1,如果目标编译器用-D_GLIBCXX_USE_CXX11_ABI=0,或者不同版本对默认值做了调整,二进制就不兼容。MinGW-w64 在 64 位下通常使用 SEH 异常模型,但不同构建版本之间也可能混入不同配置。如果异常表和 unwind 信息不一致,程序运行到异常抛出时就有可能直接崩溃。这些细节平时看不见,但一旦出问题,排错成本极高。
Boost 库本身分两部分,一部分是 header-only,例如smart_ptr、asio的多数功能,只需要头文件;另一部分是需要链接编译库的模块,比如filesystem、thread、regex、locale、system。这份预编译包要解决的就是后面这些需要编译的模块,否则你每次都要为几个库单独跑编译流程。
2.3 动态 vs 静态:为什么这份选的是动态库
写 C++ 的时候,很多人更习惯静态库,因为 exe 扔到别的机器上不用带一堆 DLL。但这个资源包选的是动态库,理由很实际:
- 体积控制:Boost 全功能静态库一个模块就可能到几十 MB,链接进 exe 后体积非常夸张。动态库独立成 DLL,exe 体积小很多。
- 分发灵活:程序依赖的 Boost 模块以 DLL 形式存在,结构清晰,多个程序可以共用同一份 DLL。
- Debug 和 Release 并存:两套动态库可以放在同一个目录下,运行时按搜索路径选择,不需要重复改工程配置。
代价是运行时必须把对应 DLL 放到 exe 旁边或加入 PATH,这一点很多人会忽略,导致程序在开发机上能跑,换台机器就报缺 DLL。更关键的是,使用动态库时必须在编译期定义BOOST_ALL_DYN_LINK这个宏。它会让 Boost 头文件按__declspec(dllimport)的方式处理导入符号,也就是告诉编译器:我们用的是动态链接。如果不加,header-only 模块可能还能编过,但需要链接的模块很容易出现“无法解析的外部符号”,这也是新手最常踩的坑之一。
3. 把 Boost 1.78 接进项目:三种集成方式与参数精讲
3.1 目录规划:解压到哪儿、环境变量怎么设
先推荐一个放法:不要解压到带空格或权限限制的路径,也不要直接扔到工程源码树里。我一般会放在一个单独的第三方目录,比如D:\ThirdParty\boost_1_78_mingw730,然后在这个目录下保留include和lib两个子目录。
接下来设置环境变量。开发期最省事的方式是写到一个批处理里,避免每次开终端都手动敲:
set BOOST_ROOT=D:\ThirdParty\boost_1_78_mingw730 set BOOST_LIBRARYDIR=%BOOST_ROOT%\lib set PATH=%BOOST_LIBRARYDIR%;%PATH%解释一下:BOOST_ROOT是 CMake 的 FindBoost 脚本识别 Boost 安装位置的约定变量;BOOST_LIBRARYDIR告诉它库文件在哪;PATH加库目录是为了让程序启动时能直接找到 DLL。即使你在链接时用-L指定了库路径,程序启动时 Windows loader 也不会记住这个路径,只会按 exe 所在目录、系统目录、PATH 的顺序搜索 DLL。所以要么把 DLL 复制到 exe 旁,要么把 lib 目录加进 PATH,二选一。
3.2 命令行编译:g++ 的 -I、-L、-l 到底怎么写
先写一个最小的测试文件,验证头文件和库都能接上:
#include <boost/filesystem.hpp> #include <iostream> int main() { boost::filesystem::path p("."); std::cout << p.filename() << std::endl; return 0; }然后编译,Release 版命令:
g++ main.cpp -o app.exe \ -ID:/ThirdParty/boost_1_78_mingw730/include \ -LD:/ThirdParty/boost_1_78_mingw730/lib \ -DBOOST_ALL_DYN_LINK \ -lboost_filesystem-mgw73-mt-x64-1_78 \ -lboost_system-mgw73-mt-x64-1_78如果是 Debug 构建,库名要换成带-d的版本:
g++ main.cpp -o appd.exe -g \ -ID:/ThirdParty/boost_1_78_mingw730/include \ -LD:/ThirdParty/boost_1_78_mingw730/lib \ -DBOOST_ALL_DYN_LINK \ -lboost_filesystem-mgw73-mt-d-x64-1_78 \ -lboost_system-mgw73-mt-d-x64-1_78参数含义拆开说:-I是指头文件搜索路径,要指到include,不是include/boost;-L是库文件搜索路径;-l后面跟的是 lib 目录下文件名去掉lib前缀和.dll.a后缀,保留从boost开始的部分。这个字段最容易写错,强烈建议先dir D:\ThirdParty\boost_1_78_mingw730\lib看一眼实际文件名。另外,链接顺序要讲究,-lboost_system放在-lboost_filesystem后面,即被依赖的库放在依赖者的后面,否则可能出现符号解析不到的情况。
3.3 CMake 集成:让 find_package 找到这套预编译库
CMake 的 FindBoost 模块对 MinGW 预编译库需要手动指路。一个可用的 CMakeLists.txt 长这样:
cmake_minimum_required(VERSION 3.16) project(boost_demo CXX) set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "" FORCE) set(BOOST_ROOT "D:/ThirdParty/boost_1_78_mingw730" CACHE PATH "" FORCE) set(Boost_NO_BOOST_CMAKE ON CACHE BOOL "" FORCE) set(BOOST_LIBRARYDIR "${BOOST_ROOT}/lib" CACHE PATH "" FORCE) find_package(Boost 1.78 REQUIRED COMPONENTS filesystem system) add_executable(app main.cpp) target_link_libraries(app PRIVATE Boost::filesystem Boost::system) target_compile_definitions(app PRIVATE BOOST_ALL_DYN_LINK)解释几个关键点:Boost_NO_SYSTEM_PATHS=ON是为了防止 FindBoost 跑去系统路径找别的 Boost 版本,尤其是 MSYS2 或 Qt 自带的那些;Boost_NO_BOOST_CMAKE=ON是强制使用 FindBoost 脚本,不依赖 Boost 官方的 CMake 配置文件,因为预编译包里通常不带;find_package(Boost 1.78 REQUIRED COMPONENTS ...)会检查版本和需要的模块。目标Boost::filesystem会自动根据CMAKE_BUILD_TYPE选择带-d后缀的 Debug 库还是不带-d的 Release 库。
MinGW Makefiles 是单配置生成器,必须显式指定构建类型:
cmake -S . -B build -G "MinGW Makefiles" \ -DCMAKE_BUILD_TYPE=Debug \ -DBOOST_ROOT=D:/ThirdParty/boost_1_78_mingw730如果不设CMAKE_BUILD_TYPE,FindBoost 会警告并使用默认的 Release 库,即使你之后用带-g的方式编译,链接的仍然是 Release 库,调试信息就对不上。
3.4 Debug/Release 库的选择:为什么 CMAKE_BUILD_TYPE 不能乱填
很多刚接触 CMake 的人会把构建类型放在 IDE 里切换,但 MinGW Makefiles 不吃这一套。它在 configure 阶段就要确定后缀是-d还是不带-d,所以规则很简单:
- 用 Debug 构建,就传
-DCMAKE_BUILD_TYPE=Debug; - 用 Release 构建,就传
-DCMAKE_BUILD_TYPE=Release; - 不要在一次 configure 之后反复切换,重新建一个 build 目录更干净。
如果项目里同时存在静态库和动态库依赖,要特别注意静态模块不要定义BOOST_ALL_DYN_LINK,动态模块必须定义。同一个 Boost 模块不能混用静态和动态,否则符号导入导出的处理会冲突。最省心的做法是全部走动态库,CMake 统一target_compile_definitions一条命令搞定。
4. 避坑:Boost 1.78 + MinGW 链接中常见的五个问题
4.1 链接时提示 cannot find -lboost_filesystem-mgw73-mt-x64-1_78
现象:命令行编译时报cannot find -lboost_filesystem-mgw73-mt-x64-1_78,但 lib 目录下明明有相同名字的.dll.a文件。
原因:常见三种。一是-L路径指向了别的目录,或者写路径时反斜杠被转义,没生效;二是库文件实际叫libboost_filesystem-mgw73-mt-x64-1_78.dll.a,但你的-l参数少了工具链或版本字段;三是文件名中的x64可能不存在,实际只有mgw73-mt-1_78,命名规则不完全一致。
解决:先dir确认 lib 目录下的真实文件名,把-l参数改成实际文件去掉lib前缀和.dll.a后缀。路径统一用正斜杠,避免转义问题。我还会加一个-v参数让 g++ 打印库搜索路径,直接看到底找了哪些目录。
4.2 头文件与库版本冲突:编译过了,链接报 undefined reference
现象:代码能编译通过,但链接时报undefined reference to boost::filesystem::...,而且报错符号很长,看不出原因。
原因:大概率是 include 路径和 lib 路径指向了两套不同的 Boost。比如 include 路径被 MSYS2 或 Qt 自带环境变量劫持,头文件版本是 1.74 甚至更老,而库文件是 1.78,符号自然对不上。另一种常见原因是BOOST_ALL_DYN_LINK没定义,导致头文件里的导入导出宏不一致,也会出现 undefined reference。
解决:在 CMake 或命令行里统一-I和-L都指向同一个包。在代码里输出BOOST_LIB_VERSION宏确认头文件版本:
#include <boost/version.hpp> #include <iostream> int main() { std::cout << BOOST_LIB_VERSION << std::endl; return 0; }如果版本对不上,检查是否有系统路径优先级劫持。另外确认编译命令里加了-DBOOST_ALL_DYN_LINK。
4.3 运行时报错找不到 libboost_filesystem-mgw73-mt-x64-1_78.dll
现象:链接成功,生成 exe,但运行时弹窗提示“由于找不到 libboost_filesystem-mgw73-mt-x64-1_78.dll,无法继续执行代码”。
原因:链接时-L只是让链接器找到.dll.a导入库,链接器会把 DLL 文件名写进 exe 的导入表,但不会把 DLL 复制到 exe 旁边。Windows 启动 exe 时按固定顺序搜索 DLL,PATH 里没有 lib 目录,exe 目录中也没有 DLL,就会报错。
解决:开发期最简单的办法是set PATH=%PATH%;D:\ThirdParty\boost_1_78_mingw730\lib。发布期把需要的 DLL 复制到 exe 同目录,或用一个脚本统一收集依赖。用 objdump 查看 exe 的依赖列表:
objdump -p app.exe | grep "DLL Name"这样能明确知道需要复制哪些文件,别一把梭把整个 lib 目录拷过去。
4.4 Debug 和 Release 库混用:程序莫名崩溃或堆损坏
现象:程序在 Debug 下运行正常,但 Release 版偶发崩溃;或者反过来,Release 工程链接了 Debug 库,运行后报堆错误。
原因:Debug 版库使用调试堆,容器的内存布局可能带有额外调试信息,和 Release 版布局不一致。如果 exe 和 Boost 库的构建类型不匹配,同一个对象在模块间传递时,分配和释放可能发生在不同的堆上,轻则崩溃,重则产生无法追踪的内存损坏。这个坑不会立刻暴露,往往到发布前才爆发。
解决:严格按构建类型选库。CMake 里让 FindBoost 自动选择,不要手动指定Boost_DEBUG_LIBRARY或Boost_RELEASE_LIBRARY去覆盖。用单配置生成器时尤其要确认CMAKE_BUILD_TYPE传对了,Debug 和 Release 用不同的 build 目录,避免缓存串味。
4.5 换了 MinGW 版本后出现 std::string ABI 相关错误
现象:同一份代码,之前用 minGW730 编译没问题,换成 MinGW-w64 GCC 8.1 后,链接报错undefined reference to std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::...。
原因:GCC 8 和 GCC 7 的 libstdc++ 符号版本不同。Boost 动态库是用 GCC 7.3 编译的,导入库里记录的是 GCC 7 的符号修饰,你用 GCC 8 编译器引用时,标准库类型布局和符号修饰对不上。这不是 Boost 的问题,是 C++ ABI 跨版本不兼容的典型现象。
解决:换回 minGW730 工具链,或者重新找对应 GCC 8 的 Boost 预编译包。不要想着用-D_GLIBCXX_USE_CXX11_ABI=0硬凑,那会引发更多诡异问题。如果项目配套的 Qt 版本自带了 MinGW 7.3.0,直接用那个编译器最省心。
5. 实战验证:用探针程序确认 Boost 1.78 能编能链能跑
5.1 探针一:用 Filesystem 验证动态库链接和运行
这个探针会用到必须链接的boost_filesystem和boost_system,能完整走一遍 include、链接、运行流程。
#define BOOST_ALL_DYN_LINK #include <boost/filesystem.hpp> #include <iostream> int main() { boost::filesystem::path current("."); if (boost::filesystem::exists(current)) { std::cout << "exists: " << boost::filesystem::absolute(current) << std::endl; } std::cout << "Boost version: " << BOOST_LIB_VERSION << std::endl; return 0; }编译命令,Debug 版:
g++ probe_fs.cpp -o probe_fs.exe -g \ -ID:/ThirdParty/boost_1_78_mingw730/include \ -LD:/ThirdParty/boost_1_78_mingw730/lib \ -DBOOST_ALL_DYN_LINK \ -lboost_filesystem-mgw73-mt-d-x64-1_78 \ -lboost_system-mgw73-mt-d-x64-1_78运行后应该看到exists: "D:/..."和Boost version: 1_78。如果运行报缺 DLL,说明 PATH 没设置好;如果输出版本不是 1_78,说明 include 路径被其他版本劫持了。BOOST_LIB_VERSION是头文件里定义的宏,直接反映当前生效的 Boost 版本,这是排查头文件混乱最快的手段。
5.2 探针二:用 Asio 的同步定时器验证 header-only 路径
Boost.Asio 的核心部分在 1.78 是 header-only,不需要额外链接库,适合验证 include 路径是否正确,也排除库选择干扰。
#define BOOST_ALL_DYN_LINK #include <boost/asio.hpp> #include <iostream> int main() { boost::asio::io_context io; boost::asio::steady_timer timer(io, std::chrono::seconds(1)); timer.wait(); std::cout << "asio timer ok" << std::endl; return 0; }编译:
g++ probe_asio.cpp -o probe_asio.exe \ -ID:/ThirdParty/boost_1_78_mingw730/include \ -DBOOST_ALL_DYN_LINK注意这里没有-L和-l,因为 Asio 不需要链接 Boost 编译库。运行会等待 1 秒后输出asio timer ok。如果编译阶段就报找不到boost/asio.hpp,说明-I路径没指到 include 目录;如果 include 能找到却报版本宏错误,就需要检查是不是有环境变量提前注入了其他 Boost。
5.3 确认 exe 到底依赖哪些 DLL 以及是否指向预期位置
编译成功只是第一步,运行时依赖必须单独确认。用 MinGW 自带的 objdump 查看导入表:
objdump -p probe_fs.exe | grep "DLL Name"输出里应该能看到libboost_filesystem-mgw73-mt-d-x64-1_78.dll和libboost_system-mgw73-mt-d-x64-1_78.dll,同时也可能看到libgcc_s_seh-1.dll、libstdc++-6.dll、libwinpthread-1.dll这些 MinGW 运行时依赖。然后用where确认实际加载路径:
where libboost_filesystem-mgw73-mt-d-x64-1_78.dll如果where找到的 DLL 不是预期路径,可以通过调整 PATH 顺序来控制。发布时直接把where列出的 DLL 都复制到 exe 同目录最保险,不要依赖目标机器上的 PATH。
6. 进阶用法:把预编译 Boost 固化成一套可复用的项目模板
6.1 用 CMake 工具链文件锁死编译器与 Boost 路径
每次手动传-DBOOST_ROOT很容易漏,换个项目又得翻笔记。我习惯写一个toolchain-mingw730.cmake,把编译器、Boost 路径固定下来。这样新建项目时只需要一行 cmake 参数,不用重复记忆。
set(CMAKE_SYSTEM_NAME Windows) set(CMAKE_C_COMPILER "D:/mingw730/bin/gcc.exe") set(CMAKE_CXX_COMPILER "D:/mingw730/bin/g++.exe") set(BOOST_ROOT "D:/ThirdParty/boost_1_78_mingw730") set(BOOST_LIBRARYDIR "${BOOST_ROOT}/lib")使用方式:
cmake -S . -B build -G "MinGW Makefiles" \ --toolchain toolchain-mingw730.cmake \ -DCMAKE_BUILD_TYPE=Debug工具链文件里的路径统一用正斜杠,避免 CMake 解析转义出问题。这样整个团队拿到手都能复现同一套环境,不会因为某个人改了 PATH 导致 Boost 版本悄悄漂移。
6.2 发布前自动收集 DLL 的检查脚本
链接动态库之后最容易翻车的环节是发布。我一般会在发布前跑一个脚本,把 exe 依赖的 Boost DLL 和 MinGW 运行时 DLL 全部复制到发布目录:
mkdir -p dist for dll in $(objdump -p app.exe | grep "DLL Name" | awk '{print $3}'); do find D:/ThirdParty/boost_1_78_mingw730/lib D:/mingw730/bin -name "$dll" -exec cp {} dist/ \; done这是 Git Bash 或 MSYS2 环境下的写法,核心是用 objdump 拿到依赖列表,再用 find 从 Boost 目录和 MinGW 目录里定位并复制。如果坚持用 cmd,就写几行固定 copy 命令,把 Qt 和 Boost 这几个固定 DLL 复制过去。从那以后,我每次拿到预编译 Boost 包都会先跑一遍探针程序确认头文件和库能对上,再丢进 CMake 模板,这个习惯帮我省掉了好几次发布前一天才发现缺 DLL 的尴尬。这个包我解压后按上面流程接入项目,一路顺畅,希望帮到你。
本文还有配套的精品资源,点击获取