ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Windows下编译Cesium-Native:从依赖管理到CMake实战

Windows下编译Cesium-Native:从依赖管理到CMake实战 1. 为什么要在Windows上折腾Cesium-Native先说一个我自己的真实经历。去年接手一个三维地理信息项目需要在桌面端嵌入一个地球渲染引擎团队一开始选的是Web方案用浏览器壳套CesiumJS。跑起来倒是快但一到大数据量模型加载就卡得不行内存占用也压不住。后来调研到Cesium-Native——也就是Cesium官方提供的C原生版本专门用来把三维地球能力嵌到桌面应用里性能比Web方案高出一大截还能直接和本地渲染管线对接。问题来了Cesium-Native的官方文档基本是面向Linux和macOS的Windows下的编译资料少得可怜。我在网上翻了一圈能参考的中文资料要么是几年前的旧版本要么语焉不详踩了一堆坑才把整个流程跑通。所以这篇内容就是把我从零到编译成功的完整过程记录下来包括每一步为什么这么做、哪些地方容易翻车、怎么排查。这篇适合谁看如果你有C基础哪怕只是入门水平知道头文件和源文件的关系、会用命令行想在Windows上编译Cesium-Native并且对CMake有一点概念或者愿意现学那这篇就是写给你的。我会尽量把每个环节讲透不假设你是个CMake老手。需要提前说明的是Cesium-Native的编译涉及不少第三方依赖整个流程不是一条命令搞定的那种。但只要你按步骤来把环境理顺后面就是等待编译的过程。我实测下来一台普通的开发机16G内存、SSD从零开始大概需要两到三个小时其中大部分时间是在下载依赖和编译。2. 编译之前必须理清的依赖关系2.1 Cesium-Native到底依赖了什么很多人一上来就clone代码然后直接cmake结果报一堆找不到库的错误。根本原因是没有搞清楚Cesium-Native的依赖结构。我把它拆成三层来看第一层是构建工具链包括CMake、Git、以及一个C编译器。Windows下编译器首选Visual Studio自带的MSVC因为Cesium-Native的很多依赖在Windows上默认按MSVC来配置。你也可以用MinGW但后面会遇到更多兼容性问题新手不建议。第二层是第三方库这是最麻烦的部分。Cesium-Native依赖的库包括但不限于依赖库用途Windows下的获取方式draco几何压缩解码源码编译或vcpkgstb图像加载头文件库直接引入glm数学运算头文件库CMake自动拉取rapidjsonJSON解析头文件库sqlite3本地缓存需要编译或找预编译版zlib压缩需要编译libcurl网络请求需要编译或找预编译版openssl加密通信需要编译最耗时第三层是Cesium自己的子模块比如cesium-native本身包含的各个组件CesiumAsync、CesiumGeometry、CesiumGltf等这些在clone时通过--recursive参数一起拉下来。2.2 为什么推荐用vcpkg管理依赖我一开始是手动一个个编译依赖库的光是openssl就折腾了大半天各种路径配置错误。后来改用vcpkg效率提升非常明显。vcpkg是微软维护的C包管理器能自动处理依赖的下载、编译和路径配置和CMake的集成也很顺滑。安装vcpkg的步骤不复杂git clone https://github.com/microsoft/vcpkg.git cd vcpkg .\bootstrap-vcpkg.bat然后设置环境变量让CMake能找到vcpkg的toolchain文件。我习惯在项目目录下直接指定而不是改全局环境变量这样不同项目之间不会互相干扰cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE[vcpkg路径]/scripts/buildsystems/vcpkg.cmake注意vcpkg默认编译的是x86版本如果你需要x64现在基本都是64位了要指定triplet为x64-windows。这个细节很多人会忽略导致后面链接时报架构不匹配的错误。2.3 Visual Studio版本的选择Cesium-Native对MSVC的版本有要求太老的版本不支持C17特性。我实测VS2019 16.10以上和VS2022都可以。安装VS的时候记得勾选使用C的桌面开发工作负载并且确保安装了Windows 10 SDK或Windows 11 SDK。有一个容易踩的坑如果你机器上装了多个版本的VSCMake可能会选错。可以在cmake命令里显式指定cmake -B build -S . -G Visual Studio 17 2022 -A x64这里的-G指定生成器-A指定架构。VS2022对应的生成器名称是Visual Studio 17 2022VS2019是Visual Studio 16 2019。写错了CMake会直接报找不到生成器。3. 从clone到第一次cmake的完整操作链路3.1 拉取代码时最容易忽略的细节Cesium-Native的仓库有不少子模块如果你直接git clone而不加--recursive后面cmake会报找不到某些源文件。正确的做法是git clone --recursive https://github.com/CesiumGS/cesium-native.git如果你已经clone了但忘了加--recursive也不用重新拉在仓库目录下执行git submodule update --init --recursive这一步会拉取所有子模块包括一些第三方库的源码。网络状况不好的话可能会失败多试几次或者配置一下git的代理这里说的是git本身的网络配置不是其他工具。拉完之后检查一下目录结构确认extern目录下有内容。如果extern是空的说明子模块没拉下来后面肯定编译不过。3.2 CMake配置阶段的参数怎么设进入cesium-native根目录创建build目录并执行cmake。我推荐把配置命令写成一个脚本方便反复调试cmake -B build -S . ^ -G Visual Studio 17 2022 ^ -A x64 ^ -DCMAKE_TOOLCHAIN_FILEC:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake ^ -DVCPKG_TARGET_TRIPLETx64-windows ^ -DCMAKE_BUILD_TYPERelease这里几个参数逐个解释-B build指定构建目录为build保持源码目录干净。-S .指定源码目录为当前目录。-G和-A指定生成器和架构前面说过了。-DCMAKE_TOOLCHAIN_FILE告诉CMake用vcpkg的工具链这样find_package才能找到vcpkg装的库。-DVCPKG_TARGET_TRIPLET指定vcpkg使用64位Windows triplet。-DCMAKE_BUILD_TYPEReleaseRelease模式编译性能更好体积更小。调试阶段可以用Debug但编译产物会大很多。执行完这条命令后CMake会开始检测编译器、查找依赖。如果一切顺利最后会输出Configuring done和Generating done。如果报错往下看第4节的排查方法。3.3 编译阶段的并行度设置配置成功后执行编译cmake --build build --config Release --parallel 8--parallel 8表示用8个线程并行编译具体数字根据你CPU核心数来定。我一般设成核心数或者核心数2。设太大了反而会因为内存不够导致编译失败尤其是编译openssl这种大库的时候。整个编译过程可能要跑几十分钟到几个小时取决于机器性能。建议第一次编译的时候盯着点因为很可能在中途某个库上报错。4. 那些让我卡了半天的报错与排查过程4.1 Could NOT find OpenSSL的三种可能原因这是我最开始遇到的一个报错CMake提示找不到OpenSSL。排查下来有三种可能第一种vcpkg没有安装openssl。解决方法是vcpkg install openssl:x64-windows第二种vcpkg装了但CMake没找到。这通常是因为CMAKE_TOOLCHAIN_FILE路径写错了或者vcpkg的安装路径里有空格。检查一下路径是否正确尽量把vcpkg放在没有空格的目录下。第三种系统里装了多个OpenSSL版本CMake找到了错误的那个。可以在cmake命令里显式指定-DOPENSSL_ROOT_DIRC:/dev/vcpkg/installed/x64-windows排查这类找不到库的问题我的经验是先确认vcpkg里到底装没装再看CMake的toolchain路径对不对最后才考虑版本冲突。按这个顺序排查大部分问题都能定位到。4.2 链接阶段的unresolved external symbol这个报错比配置阶段的报错更让人头疼因为它出现在编译后期前面可能已经编译了几十分钟。常见原因有两个一是Debug和Release混用。比如你的主项目用Release编译但某个依赖库是Debug版本链接时符号就对不上。解决办法是确保所有依赖都用同一个配置编译。用vcpkg的话它会根据你的triplet自动匹配一般不会有这个问题。但如果你是手动编译的依赖就要特别注意。二是运行时库选项不一致。MSVC有/MD和/MT两种运行时库选项前者是动态链接后者是静态链接。Cesium-Native默认用/MD如果你的依赖库用了/MT就会报符号冲突。检查方法是在CMake里加上-DCMAKE_MSVC_RUNTIME_LIBRARYMultiThreadedDLL强制统一使用动态运行时库。4.3 编译到一半内存爆了怎么办编译大型C项目时内存占用飙升是常事。我有一次编译到某个模板展开特别多的文件时16G内存直接吃满系统开始疯狂用交换分区最后编译进程被系统杀掉。解决办法有几个降低并行度把--parallel 8改成--parallel 4关闭其他占内存的程序或者增加虚拟内存。如果某个文件特别吃内存可以单独用低并行度编译那个目标其他目标正常并行。还有一个技巧是分模块编译。Cesium-Native的CMake结构支持单独编译某个targetcmake --build build --target CesiumGltf --config Release这样可以把大项目拆成小块逐个击破也方便定位是哪个模块出了问题。5. 编译成功后的验证与集成5.1 怎么确认编译产物是完整的编译完成后在build目录下会生成一堆.lib和.dll文件。但编译通过不等于产物可用还需要验证。我的做法是写一个最小的测试程序链接Cesium-Native的核心库调用一个简单功能比如创建一个CesiumGltf的Model对象。测试程序的CMakeLists.txt大概长这样cmake_minimum_required(VERSION 3.15) project(CesiumTest) find_package(cesium-native CONFIG REQUIRED) add_executable(CesiumTest main.cpp) target_link_libraries(CesiumTest PRIVATE CesiumGltf CesiumGeometry)如果这个测试程序能编译、链接并运行成功说明Cesium-Native的编译产物是完整可用的。如果链接时报错说明某些库没有正确安装或者路径不对。5.2 集成到自己项目时的路径配置把Cesium-Native集成到自己的项目里关键是让CMake找到它的配置文件。有两种方式一种是在CMakeLists.txt里指定Cesium-Native的安装路径list(APPEND CMAKE_PREFIX_PATH C:/dev/cesium-native/build) find_package(cesium-native CONFIG REQUIRED)另一种是执行cmake --install把Cesium-Native安装到一个统一目录然后把这个目录加到CMAKE_PREFIX_PATH里。后者更规范推荐使用。注意Cesium-Native的DLL文件需要和你的可执行文件放在同一目录或者放在系统PATH能找到的目录。我习惯在CMake里加一个post-build命令自动拷贝DLL省得手动操作。5.3 一个容易忽略的运行时依赖Cesium-Native在运行时会加载一些资源文件比如着色器、默认样式等。这些文件在编译产物里可能不会自动拷贝到你的输出目录。如果运行时发现地球渲染不出来或者报资源加载失败检查一下这些资源文件是否在正确的位置。我一般会在CMake里加一段add_custom_command(TARGET CesiumTest POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CESIUM_NATIVE_SOURCE_DIR}/resources $TARGET_FILE_DIR:CesiumTest/resources )这样每次编译后资源文件会自动同步到输出目录。6. 给后来者的几条实操心得6.1 环境隔离比什么都重要我强烈建议把Cesium-Native的编译环境和其他项目隔离开。具体做法是vcpkg单独装一份给Cesium-Native用不要和系统里已有的库混在一起。因为Cesium-Native依赖的某些库版本比较特定和系统里其他项目用的版本可能冲突。如果条件允许用一台专门的开发机或者虚拟机来编译编译好之后把产物拷贝到主力开发机上使用。这样能避免很多在我机器上能编译换台机器就不行的问题。6.2 保留完整的编译日志第一次编译的时候把CMake的输出重定向到文件cmake --build build --config Release --parallel 8 build_log.txt 21这样出错的时候可以搜索关键字快速定位问题。我习惯在日志里搜error和warning前者是必须解决的后者有些可以忽略但涉及链接和类型转换的warning最好也看一下可能是潜在问题的信号。6.3 版本锁定不要追新Cesium-Native的主干分支更新比较频繁有时候新提交会引入编译问题。如果你只是想用它的功能建议checkout到一个稳定的release tag而不是直接用main分支。可以用git tag查看所有版本标签选一个最近的稳定版git checkout v0.38.0 git submodule update --init --recursive这样能避免因为上游代码变动导致的编译失败。等你的项目稳定了再考虑升级版本。6.4 遇到问题先搜issue再动手改Cesium-Native的GitHub issue区有不少人遇到过类似的问题搜一下往往能找到解决方案或者至少知道原因。我遇到过一个编译错误自己折腾了两个小时没搞定结果在issue里搜到别人已经给出了workaround五分钟就解决了。所以遇到报错先别急着改代码搜一下issue和讨论区效率会高很多。6.5 编译时间比你想的长做好心理准备最后说一个心态问题。Cesium-Native的完整编译在普通开发机上跑两三个小时很正常如果机器配置低或者网络慢可能更久。不要在编译的时候频繁中断去改配置那样反而更浪费时间。我的做法是配置阶段仔细检查确认没问题后启动编译然后去干别的事等编译完成再回来验证。如果编译中途失败了先看日志定位是哪个模块出的问题解决后重新编译时CMake会跳过已经编译成功的部分只编译失败的和它依赖的模块速度会快很多。所以不要因为怕重新编译就忍着错误不改越早解决越好。
返回列表