资讯动态

CGAL 4.14 + VS2013 + Boost 1.70 + Qt 5.8 环境搭建与避坑指南

发布时间:2026/10/14 18:36:51 来源:尧图企业网站定制
1. 这套老版本组合到底在解决什么问题如果你在搜索引擎里敲下CGAL 4.14 VS2013 Boost 1.70 Qt 5.8这串关键词大概率不是出于好奇而是被某个遗留项目逼到了墙角。这套组合的每一个版本号都透着一股上一个时代的气息VS2013 是 2013 年的编译器Qt 5.8 发布于 2017 年初CGAL 4.14 是 2019 年的版本而 Boost 1.70 同样是 2019 年的产物。把它们凑在一起通常意味着你手上有一个不能轻易升级的工程——可能是依赖了某个只提供 VS2013 二进制库的第三方组件也可能是整个团队的构建服务器还锁死在旧工具链上。CGALComputational Geometry Algorithms Library本身是一个计算几何领域的重量级 C 库提供了三角剖分、凸包、布尔运算、网格生成、多边形处理等大量算法。它的特点是模板元编程用得极深对编译器的 C 标准支持有硬性要求同时又强依赖 Boost 的多个组件。Qt 在这里通常承担的是可视化交互的角色比如把 CGAL 算出来的三角网格用 QGLWidget 或 QGraphicsView 渲染出来再配上一些参数调节的界面。所以这套组合的本质是用 CGAL 做几何计算内核用 Qt 做前端展示用 Boost 补齐基础设施全部跑在 VS2013 这个老编译器上。为什么这件事值得单独写一篇因为这套组合的搭建过程里坑的密度远高于现代工具链。VS2013 对 C11 的支持是部分支持CGAL 4.14 虽然官方文档说支持 VS2013但实际编译时会遇到大量模板实例化失败、constexpr支持不完整、noexcept推导异常等问题。Boost 1.70 和 VS2013 之间也存在微妙的兼容性边界——Boost 从某个版本开始逐渐放弃对 VS2013 的官方测试1.70 恰好卡在一个还能用但需要手动打补丁的位置。Qt 5.8 相对独立但它和 VS2013 的配合需要选对安装包msvc2013 版本否则会出现链接期符号不匹配。这篇文章适合三类人第一类是被遗留项目绑住、必须在这套环境上把工程跑起来的一线开发者第二类是想理解老工具链下如何做依赖管理的技术负责人第三类是对 CGAL 感兴趣但被它的编译复杂度劝退、想找一个可复现路径的学习者。我会把整个搭建过程拆成可操作的步骤同时把每一步背后的为什么讲清楚让你不仅能把环境搭起来还能在遇到变体问题时知道往哪个方向排查。2. 四个组件的版本咬合关系与选型逻辑2.1 为什么是这四个版本而不是别的组合先看一张版本对照表把每个组件的角色和约束条件列清楚组件版本角色对 VS2013 的兼容状态关键约束Visual Studio2013 (VC12)编译器与 IDE自身仅支持部分 C11CGAL4.14计算几何算法库官方声明支持需要 Boost 1.58Boost1.70基础设施库可用但需注意1.70 是最后几个较好支持 VC12 的版本Qt5.8GUI 与可视化需选 msvc2013 包与 CGAL 无直接依赖这张表里最关键的信息是CGAL 4.14 要求 Boost 最低 1.58但并没有限制上限。那为什么偏偏选 1.70因为 Boost 1.71 之后部分库开始使用 VS2013 不支持的 C14 特性编译会直接报错。1.70 是一个甜点版本——它包含了 CGAL 4.14 需要的所有 Boost 组件比如Boost.Graph、Boost.PropertyMap、Boost.Thread同时还没有引入那些会卡死 VC12 的新语法。如果你手头只有 Boost 1.72 或更高要么降级要么就得去改 Boost 源码里的宏判断工作量不小。Qt 5.8 的选择逻辑不太一样。Qt 和 CGAL 之间没有编译期依赖Qt 只负责把 CGAL 的输出画出来。所以 Qt 版本的选择相对自由5.8 之所以常见是因为它是最后一个提供完整 msvc2013 预编译包的 LTS 附近版本。再往后的 Qt 5.9、5.12 虽然也有 msvc2013 包但部分模块的二进制兼容性开始出现细微问题。如果你只是用 Qt 的 GUI 部分QtWidgets、QtGui、QtOpenGL5.8 足够稳定。2.2 CGAL 的 header-only 特性与实际编译负担CGAL 从 5.0 开始才全面转向 header-only4.14 时代还有部分模块需要编译成库。但即便在 4.14核心的几何算法如Triangulation_2、Triangulation_3、Convex_hull_2都是 header-only 的你只需要在代码里#include对应的头文件不需要额外链接.lib。这带来一个好处你不需要单独编译 CGAL 的库文件省掉了一大块构建时间。但 header-only 也有代价。CGAL 的模板实例化非常重一个简单的Delaunay_triangulation_2实例化可能就会让编译器吃掉几百 MB 内存编译时间以分钟计。在 VS2013 上这个问题更严重因为 VC12 的模板编译器在处理深层嵌套模板时效率不高而且对auto和decltype的支持不完整CGAL 内部的一些类型推导会退化成显式类型声明进一步增加编译负担。实际经验是把 CGAL 相关的代码单独放在一个静态库项目里只暴露必要的接口给 Qt 主工程。这样做的好处是 CGAL 的模板实例化只发生一次Qt 工程不需要重复编译那些头文件。如果你把所有代码混在一个工程里每次改一行 Qt 界面代码都要重新实例化一遍 CGAL 模板开发体验会非常糟糕。2.3 Boost 1.70 的编译策略全量还是按需Boost 1.70 在 VS2013 下的编译有两种策略。第一种是跑bootstrap.bat然后b2全量编译生成所有库的.lib。第二种是只编译 CGAL 实际用到的那几个库。我推荐第二种原因很直接全量编译 Boost 在 VS2013 上大约需要 40 到 60 分钟而且会生成好几个 GB 的中间文件。CGAL 4.14 实际依赖的 Boost 库并不多主要是Boost.Thread用于并行算法Boost.System错误码Boost.Graph部分算法内部使用Boost.PropertyMap图算法辅助Boost.Atomic线程安全你可以用b2 --with-thread --with-system --with-graph --with-atomic这样的参数只编译需要的库。但要注意CGAL 的某些头文件会间接包含其他 Boost 头文件如果编译时报找不到 xxx.lib再补编译对应的库即可。这种按需编译、逐步补齐的方式比一次性全量编译更可控。提示Boost 1.70 在 VS2013 下编译时Boost.Thread可能会报一个关于boost::chrono的警告这是已知问题不影响功能。如果遇到链接错误检查是否同时链接了boost_thread和boost_chrono。3. 从零搭建环境准备与依赖安装的完整链路3.1 VS2013 的安装与 C11 支持确认VS2013 的安装本身没有太多坑但有一个关键点必须安装 Update 5。VS2013 的早期版本RTM、Update 1-4在 C11 支持上有一些 bug特别是对variadic templates和alias templates的处理。CGAL 4.14 的某些头文件会用到这些特性如果编译器版本不对会报出莫名其妙的语法错误。Update 5 是 VS2013 的最后一个累积更新也是兼容性最好的版本。安装完成后打开 VS2013 的命令行工具Developer Command Prompt for VS2013运行cl /?确认编译器版本。你应该看到类似Microsoft (R) C/C Optimizing Compiler Version 18.00.40629的输出其中40629是 Update 5 的版本号。如果是更早的版本号建议重新安装 Update 5。另外VS2013 默认不开启/std:c11这样的标准选项那个年代还没有这个开关它默认就是 C11 的部分支持模式。你不需要额外加编译选项但需要在代码里避免使用 VS2013 不支持的 C11 特性比如constexpr的复杂用法、noexcept的推导、以及std::make_unique这个在 VS2013 里没有需要自己写一个或者用 Boost 的替代。3.2 Boost 1.70 的下载、解压与编译参数Boost 1.70 的源码包可以从官方渠道获取解压到一个路径中不含空格和中文的目录比如D:\libs\boost_1_70_0。路径里有空格会导致b2工具的某些脚本解析出错这是很多人第一次编译 Boost 时踩的坑。编译步骤如下# 进入 Boost 根目录 cd D:\libs\boost_1_70_0 # 运行 bootstrap生成 b2.exe bootstrap.bat # 编译需要的库toolset 指定 msvc-12.0对应 VS2013 b2 toolsetmsvc-12.0 --with-thread --with-system --with-graph --with-atomic --with-chrono linkstatic runtime-linkstatic address-model64 stage这里有几个参数需要解释。toolsetmsvc-12.0明确告诉 Boost 用 VS2013 的编译器因为b2默认可能会找到你机器上更高版本的 VS。linkstatic和runtime-linkstatic表示生成静态库并静态链接 C 运行时这样做出来的程序不依赖 VC 运行时 DLL部署更方便。address-model64生成 64 位库如果你的项目是 32 位改成32。stage表示把生成的库文件集中放到stage\lib目录下方便后续引用。编译完成后检查stage\lib目录你应该看到类似libboost_thread-vc120-mt-s-1_70.lib的文件。文件名里的vc120表示 VS2013mt表示多线程s表示静态运行时。这些命名规则很重要后面在 VS 里配置链接器时需要对应上。3.3 CGAL 4.14 的获取与 CMake 配置要点CGAL 4.14 的源码包解压后目录结构里有一个CMakeLists.txt。虽然 CGAL 核心是 header-only 的但官方推荐用 CMake 来管理依赖和生成 VS 工程。你需要先安装 CMake建议 3.10 以上版本然后在 CGAL 源码目录下创建一个build文件夹运行 CMake GUI。CMake 配置时有几个关键变量需要设置BOOST_ROOT指向 Boost 的根目录比如D:\libs\boost_1_70_0BOOST_LIBRARYDIR指向 Boost 的库目录比如D:\libs\boost_1_70_0\stage\libCMAKE_INSTALL_PREFIXCGAL 的安装目录比如D:\libs\CGAL-4.14-installCGAL_DIR如果你之前已经安装过 CGAL这里指向安装目录点击 Configure 后CMake 会检测 Boost 的版本和组件。如果一切正常你会看到Boost_FOUND为TRUE并且列出了找到的 Boost 库。如果报错说找不到某个 Boost 库回到上一步确认是否编译了对应的组件。Configure 通过后点击 Generate 生成 VS2013 的解决方案文件。打开CGAL.sln编译INSTALL项目通常只需要编译这一个项目CGAL 的头文件会被复制到CMAKE_INSTALL_PREFIX指定的目录。这个安装目录里主要是include文件夹里面是 CGAL 的所有头文件。注意CGAL 4.14 的 CMake 脚本在 VS2013 下可能会报一个关于CGAL_USE_GMP的警告。如果你不需要精确的有理数运算可以忽略这个警告如果需要得额外编译 GMP 和 MPFR 库那又是另一个大坑建议先不启用。3.4 Qt 5.8 的安装与 VS2013 插件的配置Qt 5.8 的安装包需要选择qt-opensource-windows-x86-msvc2013-5.8.0.exe这个版本。安装时勾选Qt 5.8下的msvc2013 64-bit或 32-bit取决于你的项目架构。安装完成后你还需要安装 Qt VS Tools 插件让 VS2013 能够识别 Qt 的工程文件。Qt VS Tools 的版本需要和 VS2013 匹配。较新的 Qt VS Tools 可能不支持 VS2013你需要找 2.x 版本的插件。安装插件后在 VS2013 的菜单栏会出现 Qt VS Tools 菜单里面可以设置 Qt 的版本路径。添加一个 Qt 版本指向C:\Qt\Qt5.8.0\5.8\msvc2013_64根据你的实际安装路径调整。配置完成后新建一个 Qt 工程测试一下。如果能看到 Qt 的工程模板并且编译一个简单的窗口程序能跑起来说明 Qt 环境就绪。4. 把四个组件串起来工程配置与第一个可运行示例4.1 VS2013 工程的头文件路径与库路径设置现在假设你已经有了一个 VS2013 的 C 工程想在里面同时使用 CGAL、Boost 和 Qt。打开工程的属性页需要配置以下几个地方C/C - 常规 - 附加包含目录添加D:\libs\CGAL-4.14-install\include D:\libs\boost_1_70_0 C:\Qt\Qt5.8.0\5.8\msvc2013_64\include C:\Qt\Qt5.8.0\5.8\msvc2013_64\include\QtWidgets C:\Qt\Qt5.8.0\5.8\msvc2013_64\include\QtGui C:\Qt\Qt5.8.0\5.8\msvc2013_64\include\QtCore C:\Qt\Qt5.8.0\5.8\msvc2013_64\include\QtOpenGL链接器 - 常规 - 附加库目录添加D:\libs\boost_1_70_0\stage\lib C:\Qt\Qt5.8.0\5.8\msvc2013_64\lib链接器 - 输入 - 附加依赖项添加libboost_thread-vc120-mt-s-1_70.lib libboost_system-vc120-mt-s-1_70.lib libboost_graph-vc120-mt-s-1_70.lib libboost_atomic-vc120-mt-s-1_70.lib libboost_chrono-vc120-mt-s-1_70.lib Qt5Core.lib Qt5Gui.lib Qt5Widgets.lib Qt5OpenGL.lib这里最容易出错的是 Boost 库的文件名。如果你编译 Boost 时用的是runtime-linkstatic文件名里会有-s如果是runtime-linkshared则没有-s但需要额外链接libboost_thread-vc120-mt-1_70.lib这样的动态版本。库文件名必须和编译时的参数完全对应否则会出现 LNK2019 未解析符号的错误。4.2 一个最小的 CGAL Qt 示例凸包计算与显示为了验证环境是否真的可用我建议从一个最小的示例开始用 CGAL 计算一组随机点的凸包然后用 Qt 把点和凸包画出来。这个示例足够简单但涵盖了 CGAL 算法调用、Qt 界面、以及两者之间的数据传递。先看 CGAL 部分的代码// convex_hull.h #pragma once #include vector #include CGAL/Exact_predicates_inexact_constructions_kernel.h #include CGAL/convex_hull_2.h typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef K::Point_2 Point2; std::vectorPoint2 computeConvexHull(const std::vectorPoint2 input);// convex_hull.cpp #include convex_hull.h std::vectorPoint2 computeConvexHull(const std::vectorPoint2 input) { std::vectorPoint2 result; CGAL::convex_hull_2(input.begin(), input.end(), std::back_inserter(result)); return result; }这段代码里Exact_predicates_inexact_constructions_kernel是 CGAL 里最常用的内核之一。它的特点是判定精确、构造近似——在比较两个点是否相等、判断点是否在直线左侧这类谓词运算上使用精确算术而在计算交点坐标这类构造运算上使用浮点数。这样做的好处是凸包算法的正确性有保证不会因为浮点误差把凸包算错同时性能又比全精确内核好很多。Qt 部分创建一个QWidget子类重写paintEvent// hull_widget.h #pragma once #include QWidget #include QVector #include QPointF class HullWidget : public QWidget { Q_OBJECT public: explicit HullWidget(QWidget* parent nullptr); void setData(const QVectorQPointF points, const QVectorQPointF hull); protected: void paintEvent(QPaintEvent* event) override; private: QVectorQPointF m_points; QVectorQPointF m_hull; };// hull_widget.cpp #include hull_widget.h #include QPainter HullWidget::HullWidget(QWidget* parent) : QWidget(parent) {} void HullWidget::setData(const QVectorQPointF points, const QVectorQPointF hull) { m_points points; m_hull hull; update(); } void HullWidget::paintEvent(QPaintEvent*) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.fillRect(rect(), Qt::white); // 画所有点 painter.setPen(Qt::NoPen); painter.setBrush(Qt::blue); for (const auto p : m_points) { painter.drawEllipse(p, 3, 3); } // 画凸包 painter.setPen(QPen(Qt::red, 2)); painter.setBrush(Qt::NoBrush); if (m_hull.size() 1) { for (int i 0; i m_hull.size(); i) { painter.drawLine(m_hull[i], m_hull[(i 1) % m_hull.size()]); } } }在主窗口里生成随机点调用 CGAL 计算凸包然后把结果转成QPointF传给HullWidget。这里有一个细节CGAL 的Point_2坐标是double类型Qt 的QPointF也是double所以转换很直接用CGAL::to_double(p.x())即可。4.3 编译时最常见的三类错误与排查顺序第一次编译这个示例你大概率会遇到错误。根据我的经验错误集中在三类第一类找不到头文件。报错信息是Cannot open include file: CGAL/xxx.h。这说明附加包含目录没配对或者 CGAL 的安装路径不对。检查CGAL-4.14-install\include下是否有CGAL文件夹如果没有说明 CMake 的 INSTALL 步骤没成功。第二类链接错误 LNK2019。报错信息是unresolved external symbol通常跟 Boost 或 Qt 的库有关。先检查库文件名是否和实际文件一致再检查库目录是否配对了。如果错误涉及boost::thread相关的符号确认是否链接了libboost_thread和libboost_chrono。第三类模板实例化错误 C2783 或 C2893。这类错误通常出现在 CGAL 的头文件里报错信息很长涉及模板参数推导失败。这往往是因为 VS2013 的 C11 支持不完整某些 CGAL 头文件里的auto或decltype用法无法被正确解析。解决办法是升级到 VS2013 Update 5或者在 CGAL 头文件里手动替换那些不支持的语法不推荐工作量大。如果实在无法解决考虑换用 CGAL 4.11 或 4.12它们对 VS2013 的兼容性更好。排查顺序建议是先解决头文件问题再解决链接问题最后处理模板错误。因为头文件问题会导致编译直接中断链接问题在编译通过后才会出现模板错误则可能被前两类问题掩盖。5. 让工程真正可用性能调优与日常开发中的经验5.1 编译速度优化预编译头与模板实例化控制CGAL 工程的编译速度是一个绕不开的话题。在 VS2013 上一个中等规模的 CGAL 工程全量编译可能需要 10 到 20 分钟。有几个手段可以显著改善使用预编译头stdafx.h。把 CGAL、Boost、Qt 的常用头文件都放进stdafx.h然后在工程设置里开启预编译头。这样这些头文件只需要编译一次后续的编译会快很多。但要注意预编译头里不要放模板实例化很重的头文件否则预编译头本身就会编译很久。把 CGAL 代码隔离到静态库。前面提过CGAL 的模板实例化只发生一次Qt 工程只链接静态库不直接包含 CGAL 头文件。这样做还有一个好处静态库可以单独编译不需要每次改 Qt 界面都重新编译 CGAL 部分。控制模板实例化的数量。CGAL 的每个内核和算法组合都会产生独立的模板实例。如果你同时用了Exact_predicates_inexact_constructions_kernel和Exact_predicates_exact_constructions_kernel编译器会为两套内核各生成一份代码。尽量统一使用一种内核除非确实需要精确构造。5.2 运行时性能内核选择与算法参数CGAL 的内核选择对运行时性能影响很大。Exact_predicates_inexact_constructions_kernel在大多数场景下是最佳选择因为它的谓词运算是精确的不会出现浮点误差导致的错误判定而构造运算是近似的速度快。但如果你需要精确的交点坐标比如做布尔运算那就得用Exact_predicates_exact_constructions_kernel代价是速度慢一个数量级。另一个影响性能的因素是算法的参数。比如Delaunay_triangulation_2在插入大量点时如果点的分布很不均匀三角剖分的质量会下降后续的网格生成会更慢。可以在插入点之前先做一次空间排序或者使用spatial_sort函数对点进行预处理。Qt 这边的性能瓶颈通常在渲染。如果你要画几十万个点用QPainter::drawEllipse逐个画会非常慢。这时候应该改用QGraphicsView框架或者直接用 OpenGL 渲染。Qt 5.8 的QOpenGLWidget已经比较稳定配合QOpenGLBuffer和QOpenGLShaderProgram可以做到百万级点的实时渲染。5.3 版本升级的边界什么时候该放弃这套组合这套组合的寿命是有限的。VS2013 已经停止支持多年CGAL 的新版本5.x 之后逐渐放弃对 VS2013 的兼容Boost 也在持续提高编译器门槛。如果你发现以下信号说明该考虑升级了CGAL 的新功能比如某些 3D 算法在 4.14 里没有而升级 CGAL 又要求 VS2015 以上Boost 的某个新库比如Boost.Beast、Boost.JSON在 1.70 里没有而项目又需要Qt 的新特性比如 Qt 5.12 的QML改进无法使用编译时间越来越长开发效率明显下降升级路径通常是VS2013 - VS2015 或 VS2017CGAL 4.14 - CGAL 5.xBoost 1.70 - Boost 1.75Qt 5.8 - Qt 5.12 或 5.15。每一步升级都需要重新验证依赖关系工作量不小但长期来看是值得的。如果暂时不能升级至少要把工程结构做好隔离CGAL 相关的代码放在独立的静态库里Qt 界面代码不直接依赖 CGAL 头文件Boost 的使用限制在少数几个模块里。这样将来升级时只需要替换静态库的实现界面代码基本不用动。6. 几个容易被忽略的细节与我的实际体会6.1 字符集与运行库的一致性VS2013 工程默认使用 Unicode 字符集而 Boost 和 CGAL 的某些库在编译时可能用的是多字节字符集。如果出现链接错误检查工程属性里的字符集设置是否和 Boost 编译时的一致。另外运行库选项/MT还是/MD也必须和 Boost 编译时的runtime-link参数对应。我见过太多因为/MT和/MD混用导致的 LNK2005 错误排查起来很费时间。6.2 Qt 的 moc 与 CGAL 头文件的冲突Qt 的 moc元对象编译器会扫描头文件里的Q_OBJECT宏生成额外的 C 代码。如果某个头文件同时包含了Q_OBJECT和 CGAL 的头文件moc 可能会因为无法解析 CGAL 的模板语法而报错。解决办法是把 CGAL 相关的代码放在单独的类里这个类不继承QObject也不包含Q_OBJECT宏。Qt 的界面类只调用这个类的接口不直接包含 CGAL 头文件。6.3 调试模式下的性能陷阱CGAL 在 Debug 模式下会开启大量断言检查运行速度比 Release 模式慢几十倍。如果你在 Debug 模式下测试一个包含几万个点的三角剖分可能会等上几分钟。建议在开发阶段就用 Release 模式做性能测试Debug 模式只用来排查逻辑错误。另外VS2013 的 Debug 模式对迭代器的检查也很严格CGAL 的某些算法在 Debug 下会触发迭代器越界断言而在 Release 下正常运行。遇到这种情况先确认是不是真的越界如果不是可以在 CGAL 的配置里关闭部分断言。6.4 一个关于 Boost 1.70 的小坑Boost 1.70 在 VS2013 下编译Boost.Thread时可能会报一个关于boost::chrono::steady_clock的警告。这个警告不影响功能但如果你开启了将警告视为错误/WX编译会失败。解决办法是在 Boost 的编译参数里加上cxxflags/wd4996来禁用特定警告或者在工程设置里关掉/WX。我个人的习惯是关掉/WX因为 CGAL 和 Boost 的头文件里总会有一些无害的警告逐个处理不现实。这套环境搭建下来最深的体会是老工具链的问题不在于单个组件有多难搞而在于它们之间的交互边界模糊。CGAL 说支持 VS2013但没说支持到什么程度Boost 说兼容 VC12但没保证所有库都能编译Qt 说提供 msvc2013 包但没承诺和 CGAL 的模板代码和平共处。真正的工作量在于把这些模糊地带一个个试出来然后找到稳定的配置组合。一旦跑通了这套环境其实相当可靠毕竟这些版本都是经过大量项目验证的。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑