CCCoreLib编译集成指南:VS2019生成lib/dll并在QtCreator中调用 简介VS2019 编译产出的 CCCoreLib 源码、静态库lib与动态库dll整合包面向需要在 QtCreator 工程中调用 CloudCompare 核心算法的开发者与研究者。压缩包共 102 个文件包含 63 个 h 头文件、34 个 cpp 源文件以及 pro 工程文件、hpp、lib、dll 各 1 个整体仅 567KB结构清晰便于快速定位。算法模块覆盖点云读取、八叉树邻域搜索、几何特征分析、自动配准、手动分割、距离计算等常用功能lib 与 dll 同时具备可灵活选择静态链接或动态加载直接加入 QtCreator 工程即可运行省去在 VS2019 中自行配置依赖与编译的步骤。对想深入理解三维点云处理原理的读者还可对照源码研读各模块实现便于基于 CloudCompare 进行二次开发与性能优化。目前已有 492 人学习下载适合作为科研项目或实际工程的起步素材。 做点云处理项目的人十有八九绕不开 CloudCompare。它里面那套点云配准、法线估计、八叉树加速算法放到自己的 Qt 工具里用效果确实好但总不能把整个 CloudCompare 界面一起塞进来。于是最常用的方案就是把它的核心算法库 CCCoreLib 抽出来拿到源码再用 vs2019 编译器编出 lib 和 dll最后在一个 QtCreator 工程里链接、调用。听起来不算复杂实际走一遍就会发现编译器匹配、依赖项、运行时 dll 搜索、导出符号每一步都有暗坑。这篇文章就按我实际的折腾过程把从源码到 QtCreator 工程跑通的完整路径讲清楚。需要说明的是这里说的“lib 和 dll”不是某个第三方打包的闭源组件而是 CCCoreLib 在 Windows 上用 MSVC 编译后的标准产物lib 作为链接时的导入库dll 作为运行时的真实实现。只要环境匹配这套组合在 QtCreator 里就能被正常使用。1. 先弄明白CCCoreLib 里到底装着哪些东西为什么跟 CloudCompare 有关系1.1 核心库的功能和定位CCCoreLib 在 CloudCompare 项目里的地位相当于引擎。CloudCompare 界面上的各种按钮最终绝大多数都会落到这个库去执行。点云相关的数据结构比如点云对象、网格对象、标量场在这里定义做空间索引用的八叉树在这里实现ICP 配准、RANSAC 平面分割、点云距离计算、法线估计这些算法同样由这个库提供。官方把整套项目按“界面层”和“算法层”拆开CCCcoreLib 属于算法层理论上不依赖 Qt 界面框架所以可以相对干净地作为独立库被别的 C 工程使用。但“不依赖 Qt”不等于“零依赖”它默认会用 Eigen 做矩阵和向量运算部分高级模块还依赖 Boost这就给第一次编译制造了门槛。实际项目里你不一定需要把整个 CloudCompare 拉过来。如果只需要点云基础结构和常用算法单独维护一个 CCCoreLib 的源码副本编译后给 Qt 工程调用是最轻量的做法。网上搜“CCCoreLib 源码、lib、dll”搜到的资源本质上也都是在帮你省掉这一步。1.2 源码、lib、dll 三者分别代表什么拿到打包资源后首先要分清三个部分的用途否则很容易用错。源码是完整的算法实现。它最重要的作用不是“跑起来”而是让你能够重新编译、裁剪和调试。如果只给别人一个 dll没有对应版本的源码头文件后面想改算法或排查崩溃基本无从下手。尤其是 C 项目头文件是 ABI 契约的一部分缺了头文件光有库文件等于废物。lib 在 MSVC 环境下有两种身份。如果编译出来的是静态库lib 本身包含全部代码链接之后就不再需要 dll如果编译出来的是动态库lib 只是导入库里面没有算法实现只告诉链接器“某个符号在哪个 dll 里”真正程序启动时还得找到 dll。别人给你“vs2019 编译器的 lib 和 dll”绝大多数情况下指的都是后者也就是动态库加上配套导入库。dll 才是算法实现的最终载体程序运行时必须能在搜索路径里找到它。找不到的话Windows 会直接弹“由于找不到 CCCoreLib.dll无法继续执行代码”的对话框或者直接在 QtCreator 的应用程序输出窗口里报错。2. 用 VS2019 编译前的环境检查这一步决定你后面能不能顺利跑通2.1 编译器工具链的统一是硬前提很多人在 QtCreator 里卡住不是代码写错而是工具链没统一。既然项目标题写明了“vs2019 编译器”那整个工程从 Qt 库到 CCCoreLib再到你自己写的代码都尽可能使用同一套 MSVC 工具链。Qt 官方在 Windows 上的安装包会区分成很多版本MSVC2019 64bit、MinGW 64bit 等。MinGW 使用的是 GCC 的 ABI和 MSVC 生成的 lib/dll 完全不兼容。哪怕 MinGW 能正常编译你的 Qt 工程也没法链接到 vs2019 编出来的 .lib 上链接阶段会出现大量 “undefined reference” 或 “cannot find -l” 这类莫名其妙的问题。所以QtCreator 里必须创建一个 MSVC2019 对应的 KitQt 库也选安装器里带有 “MSVC2019” 字样的版本。Visual Studio 2019 则需要装好“使用 C 的桌面开发”工作负载这套东西不只是为了用 IDE更是为了保证系统里有 MSVC v142 编译器和 Windows SDK。2.2 依赖项准备Eigen、Boost 和 CMake编译前有三样东西要提前备好。我把它们列成表格方便对照。依赖项是否必需用途备注CMake必需构建系统建议 3.20 以上Windows 版本即可Eigen必需向量与矩阵运算纯头文件库不需要编译只需指定路径Boost可选部分高级算法实现第一次建议关闭能省掉一堆麻烦OpenMP可选并行加速MSVC 默认支持按需开启Eigen 是最省心的依赖下载后解压到固定目录比如C:/dev/eigen它的目录下应该有Eigen/子目录CMake 配置时把路径指过去就行。Boost 则完全不同Windows 上需要先用 b2 工具自己编译出库文件构建过程又长又有版本雷区如果不是需要极个别算法第一次编译 CCCoreLib 时完全可以把相关选项关掉。我习惯用 CMake GUI 而不是命令行做第一次配置因为可视化界面能直接看到哪些选项开启了方便把 Boost、测试、示例这些暂时用不到的模块全部取消勾选。CMake 版本不要太老老版本在对第三方依赖的探测上有时候会给出误导性错误。3. 从源码构建出 lib 和 dll完整操作记录3.1 CMake 配置时的几个关键选项假设你已经把源码解压到了C:/dev/CCCoreLib打开 CMake GUI源码目录填这个路径构建目录填一个独立目录比如C:/dev/CCCoreLib/build-vs2019。点击 Configure 后会弹出发行版选择对话框生成器选 “Visual Studio 16 2019”平台选择 x64千万别默认成 Win32否则编出来的库在 64 位 Qt 工程里没法用。Configure 完成后列表里会出现一堆选项重点关注这几个BUILD_SHARED_LIBS决定生成动态库还是静态库。要给别人提供“lib dll”就打开这个。EIGEN3_INCLUDE_DIR或Eigen3_DIR如果显示 NOTFOUND要手动指到 Eigen 的解压目录。Boost 相关选项能关全关比如USE_BOOST、CCCoreLib_USE_BOOST这类名字的选项。测试或示例相关关闭减少编译时间和潜在报错。Configure 结束后如果界面里没有红色错误项点击 Generate构建目录里会生成一个*.sln解决方案文件这就是 VS2019 可以用的工程。3.2 编译、产物的位置和简单验证编译可以用两种方式。一种是直接打开生成的.sln在 Visual Studio 2019 里选择 Release x64右键生成另一种是命令行cmake --build C:/dev/CCCoreLib/build-vs2019 --config Release --target CCCoreLib命令行方式更适合写进脚本。编完之后去构建目录下的 Release 文件夹找产物通常路径是C:/dev/CCCoreLib/build-vs2019/Release/CCCoreLib.dll和CCCoreLib.lib。头文件在源码的src目录或include目录下具体看源码分支的目录组织。拿到产物后先别急着开到 Qt 里。我建议先用一个极小的控制台程序验证链接是否正常避免后面所有问题都混在一起。代码可以很简单#include CCVector3.h int main() { CCCoreLib::CCVector3d v(1.0, 2.0, 3.0); return v.norm2() 0.0 ? 0 : 1; }编译时加上头文件路径链接时加上CCCoreLib.lib如果这一步能通过至少说明“导入库 头文件 dll”这一套是匹配的。如果这里就报链接错误那问题出在库的层面和 Qt 工程无关先回头检查是不是混用了不同版本的产物。4. 让 QtCreator 工程正确消费这个库.pro 配置与链接方式4.1 选择正确的 KitMSVC 工具链不是可选项假设你已经建好了 Qt Widgets 工程打开左侧 “Projects”在 Build 设置里看 Kit。必须选择带 MSVC2019 标识的那个 Kit不能选 MinGW。如果列表里没有 MSVC2019 Kit回到 Qt 安装器确认是否安装了带对应编译器的版本并在 QtCreator 的 “Options - Kits” 里手动指定编译器、调试器和 Qt 版本。这里有一个版本细节Qt 官方安装器里新一点的 Qt 6 版本可能自带的是 MSVC2022 工具链和 vs2019 不是同一个编译器。虽然 MSVC 库在多数情况下能在不同小版本间互链但如果你拿到的 CCCoreLib 明确标注了“vs2019 编译器”那最好让 QtCreator 里的 Qt 与编译器也保持在 MSVC v142 这个年代避免 ABI 层面出幺蛾子。4.2 在 .pro 文件中添加头文件和库对 qmake 工程在 .pro 文件里添加win32-msvc* { INCLUDEPATH C:/dev/CCCoreLib/src LIBS C:/dev/CCCoreLib/build-vs2019/Release/CCCoreLib.lib }注意LIBS里加的是.lib导入库不是.dll。CCCoreLib 的头文件里自带导出宏你在自己的工程中使用时不需要额外定义导出相关的宏只需要正常包含头文件并链接导入库。如果项目用的是 CMake那更推荐直接在 QtCreator 里打开 CMakeLists.txt然后用add_subdirectory引用源码或者把预编译好的导入库注入到目标里# 方式一把源码作为子目录一起编译 add_subdirectory(C:/dev/CCCoreLib ${CMAKE_BINARY_DIR}/CCCoreLib) target_link_libraries(myapp PRIVATE CCCoreLib) # 方式二使用已编译好的导入库 add_library(CCCoreLib SHARED IMPORTED) set_target_properties(CCCoreLib PROPERTIES IMPORTED_IMPLIB C:/dev/CCCoreLib/build-vs2019/Release/CCCoreLib.lib IMPORTED_LOCATION C:/dev/CCCoreLib/build-vs2019/Release/CCCoreLib.dll )方式一的好处是编译和链接同步调试时能直接跟到 CCCoreLib 源码内部适合需要深入定制的场景。方式二更清爽适合把库当黑盒用。4.3 运行时 DLL 的处理策略链接成功不等于运行成功。Windows 找 dll 的顺序大致是可执行文件所在目录、系统目录、PATH 环境变量。QtCreator 默认把可执行文件输出到 build 目录下的 debug 或 release 子目录而你的 CCCoreLib.dll 可能还在build-vs2019/Release里运行时会找不到。最省心的办法是在 .pro 里加一条构建后复制命令把 dll 直接拷到 exe 旁边CONFIG(debug, debug|release) { DESTDIR $$OUT_PWD/debug } else { DESTDIR $$OUT_PWD/release } QMAKE_POST_LINK $$quote(cmd /c copy /Y C:/dev/CCCoreLib/build-vs2019/Release/CCCoreLib.dll $$DESTDIR\\)这样每次编译完成dll 都会自动出现在程序输出目录。如果 CCCoreLib 还额外依赖其他 dll也采用同样方式复制。另外提醒一句QMAKE_POST_LINK在 Windows 下容易因为路径空格出问题用$$quote包一层可以减少很多怪异的解析错误。5. 我踩过的几个真实坑动态库导出、调试版本混用和路径依赖5.1 导出符号不一致导致链接失败这个问题最容易出现在“源码、lib、dll 不是同一份构建产物”的情况下。CCCcoreLib 的公共头文件里定义了导出宏大致逻辑是#ifdef CCCORELIB_EXPORTS #define CC_CORE_LIB_EXPORT __declspec(dllexport) #else #define CC_CORE_LIB_EXPORT __declspec(dllimport) #endif编译 CCCoreLib 时编译器会定义CCCORELIB_EXPORTS所有标了CC_CORE_LIB_EXPORT的符号导出到 dll你使用库时不定义这个宏头文件里的声明就变成dllimport链接器会去导入库里找对应符号。如果你拿到的头文件声明了一堆类成员但实际 dll 里没导出或者你用了另一个版本的 dll链接阶段就会报 “unresolved external symbol”。这种错误非常迷惑因为代码本身没写错纯粹是二进制不匹配。解决方式只有一个头文件、lib、dll 必须来自同一次编译不要混搭。5.2 Debug/Release 与运行库混用这是 Windows 下最阴间的坑之一。MSVC 运行时库分成几种模式Release 默认可能是/MDDebug 默认是/MDd。如果你用 Release 方式编译 CCCoreLib却在 Debug 的 Qt 工程里链接了它经常会出现LNK2038 mismatch detected for RuntimeLibrary这类错误。即使链接过了程序运行起来也可能出现内存布局不一致导致的崩溃。这个坑在同时使用 Qt、CCCoreLib、其他第三方库时最容易爆发。Qt 官方安装包会区分libQt5Cored.a这类 debug 版本CCCoreLib 同样需要准备 Release 和 Debug 两套产物。我的习惯是在 CMake 配置里分别建build-vs2019-release和build-vs2019-debug两个构建目录Debug 版编一次Release 版编一次。然后在 .pro 里根据CONFIG(debug, debug|release)判断该选哪份 libCONFIG(debug, debug|release) { LIBS C:/dev/CCCoreLib/build-vs2019-debug/Debug/CCCoreLib.lib } else { LIBS C:/dev/CCCoreLib/build-vs2019-release/Release/CCCoreLib.lib }QtCreator 的 Kit 里也最好保证 Debug 和 Release 都配置同一个 MSVC 工具链避免一边用 MSVC 一边用 MinGW 调试。5.3 依赖没有随包带走即使 CCCoreLib.dll 出现在 exe 旁边如果它内部还依赖别的第三方 dll仍然可能运行时报错。Windows 的提示一般会非常抽象比如“无法定位程序输入点于动态链接库”或直接弹0xc000007b第一次遇到往往一头雾水。排查这类问题我习惯用 Dependencies 这类检查工具打开 CCCoreLib.dll看它的直接依赖列表一个个核对缺失项。不过更省心的做法是在编译阶段就把可选依赖全部关掉让 CCCoreLib 的 dll 只依赖系统自带的 DLL。一个干净的 dll 拿到任何 Qt 工程里都不会因为“缺这个缺那个”而翻车。6. 少走弯路关于“拿来直接用”和“集成源码”的选择如果只是想快速验证算法效果可以直接使用别人按“vs2019 编译器”编译好的库但必须确认几件事你是 64 位工程你有和该 dll 匹配的头文件lib 导入库也一并提供。只给一个 dll 却没有任何头文件的情况下基本没法在 C 工程里正常用因为 C 没有稳定 ABI必须用匹配的头文件告诉编译器这些类和方法长什么样。另一种很适合长期维护的做法是把 CCCoreLib 源码直接作为一个子目录加入你的 CMake 工程用add_subdirectory和主工程一起编译。这样源码、头文件、lib、dll 全部从同一份代码生成版本错乱概率几乎为零。代价是首次编译时间变长不过后续有增量编译缓存其实影响不大。我个人建议第一次尝试时不要直接塞进大工程。建一个只有一个按钮的 Qt 项目调用一个 CCCoreLib 里的基础功能比如计算两个点之间的距离跑通了再往业务代码里扩展。这个最小验证过程能把环境问题全部隔离在工程之外排查起来效率高得多。等你把整套链路摸熟再决定是继续用预编译库还是把源码管理进自己的项目里。本文还有配套的精品资源点击获取