Windows下OSG+OSGEarth+GDAL 3.12编译实战:CMake配置与版本匹配 前阵子刚好要在Windows上把这套组合捞起来OSG 3.6.5 OSGEarth 3.7.2 GDAL 3.12要做三维地形数据调度和矢量数据可视化方向的预研。网上的编译教程大多停留在OSGEarth 2.x时代照着走一遍几乎没戏。折腾了一个周末把依赖顺序、CMake配置、版本匹配这些坑挨个踩了一遍最终跑通了。这篇记录就把完整的编译流程和排查链路写出来给后面接手的人省点时间。适合同样要在Windows上搭建这套三维渲染GIS栈的C开发同学也适合想搞懂CMake下依赖库是怎么被串起来的读者。这套组合的定位其实很清晰OSG负责三维场景渲染OSGEarth在OSG之上做地球分块调度、地形影像加载、矢量数据绑定GDAL则是底下兜底的数据读写层。三者加起来就是一个标准的开源三维GIS开发基座。编译顺序有硬性要求必须先编GDAL再编OSG最后才是OSGEarth因为OSGEarth的CMake配置需要同时找到GDAL和OSG。1. 版本选型与依赖关系为什么是这三个版本很多人上来就直接开编结果卡在五花八门的报错上。我建议先花半小时搞清楚版本之间的关系。OSG 3.6.5是OpenSceneGraph 3.6系列的最后一个维护版本状态最稳。OSGEarth 3.7.2对应的是新架构的REX引擎相比老版2.x它默认启用了REX渲染路径地形分块调度性能提升非常明显。GDAL 3.12则是目前比较新的稳定线3.9之后GDAL彻底转向以CMake为主构建这对Windows用户是好事以后不用再折腾autotools那套东西了。三者之间的依赖关系可以这样理解OSGEarth直接依赖OSG的osgDB、osgUtil、osgViewer、osgText等库运行时需要加载OSG插件。OSGEarth的Feature、地形渲染、影像处理依赖GDAL提供的数据读取与坐标变换能力。OSG本身不依赖GDAL但OSGEarth的CMake会把两者做深度绑定。GDAL处在最底层它的编译结果会被OSGEarth以gdal.lib头文件的方式链接进去。版本兼容性上要注意一个点OSGEarth 3.7.2对CMake版本要求不低官方写的是3.16以上但实际在我们这边用3.16遇到过一次策略问题建议直接上3.20以上的版本省得适配。另外这套组合在Windows下的构建工具链我强烈建议用Visual Studio 2019或2022社区版完全够用。不应该用MinGW因为OSGEarth的第三方依赖尤其是GDAL和Curl在MSVC环境下更顺滑MinGW的调试信息对接和DLL依赖处理都麻烦。2. 环境准备编译开始前必须做好的三件事这块内容看起来基础但恰恰是新手最容易翻车的地方。编译失败的第一大原因不在代码层面而在环境层面。2.1 工具链与目录规划我用的工具链是Visual Studio 2022版本号对应用的是v143工具集。如果你的机器装的是VS2019对应v142理论上也能跑到但编译OSGEarth 3.7.2时我没在VS2019上验证过所以不敢打包票。CMake版本我用的3.28直接去官方下载最新的Windows x64安装包就行。装的时候务必勾选Add CMake to the system PATH for all users不然命令行里敲cmake会找不到。目录规划非常关键。如果你的项目不止你一个人参与那目录结构最好固定并共享。我自己用的是这样一个结构D:\3rdparty ├── build # 所有源码的构建目录临时 ├── install # 所有库的最终安装目录头文件、lib、bin ├── src # 源码解压目录其中src下放的是gdal-3.12.0OpenSceneGraph-3.6.5osgearth-3.7.23rdpartyOSG的三方依赖源码后文会细说install下按库名分子目录比如install\gdal、install\osg、install\osgearth。这样做的好处是OSGEarth编译时通过CMAKE_PREFIX_PATH一次性指到install根目录CMake就能自动按标准目录结构找到include、lib、bin。这个做法比手动一个一个指定GDAL_DIR、OSG_DIR省心太多。2.2 第三方依赖的两种管理方式OSG和OSGEarth都有一堆第三方依赖比如zlib、libpng、libjpeg、tiff、curl、freetype、geos。管理方式有两种第一种用vcpkg。vcpkg install gdal osg osgearth一行装完确实香但它把版本锁得很死如果你想精确控制OSG 3.6.5和OSGEarth 3.7.2这个组合vcpkg的版本不一定对得上而且三方库和项目本身的Debug/Release配置容易互相污染。第二种手动去官方网站下载预编译依赖包或者源码编译。我采用的是源码编译预编译包混合的白嫖路径OSG的三方依赖直接用官方推荐的预编译包下面会说到GDAL用自己的源码编OSGEarth的其他依赖curl、geos用vcpkg单独导出或者下载官方二进制。这里有个通行经验不用害怕依赖多只要把全部依赖放在同一个prefix目录下让CMake通过CMAKE_PREFIX_PATH一次性找到大方向就不会乱。2.3 什么情况下建议直接用预编译包事实上OSG官方在GitHub的Releases页面提供了Windows下的预编译依赖包比如OpenSceneGraph-3.6.5-VC2022-64-Release-3rdParty.zip里面包含zlib、libpng、libjpeg、tiff、curl、freetype等OSG必需的三方库。这个预编译包和OSG 3.6.5源码的CMake配置是对应的直接下载解压配置OSG时指定一下就行。不过注意这个3rdParty包是Release模式下编译的如果后续OSGEarth或者你的工程需要Debug版本的OSG这个预编译包里的三方库是Release不匹配会导致LNK2038或运行时崩溃。所以如果你确定全链路只出Release包直接用预编译三方包如果有Debug需求老老实实把三方库也用Debug编一遍。3. GDAL 3.12 编译最底层那块积木GDAL编译是整个链条里最直给的一步因为3.12已经完全切换到CMake构建没有太多让你自由发挥的空间。恰恰因为这样反而要认真对待几个关键选项不然编出来的库后面OSGEarth不认识。3.1 配置命令我的做法是在源码目录外新建一个build目录然后执行cmake -S D:\3rdparty\src\gdal-3.12.0 -B D:\3rdparty\build\gdal \ -DCMAKE_INSTALL_PREFIXD:\3rdparty\install\gdal \ -DCMAKE_BUILD_TYPERelease \ -DBUILD_SHARED_LIBSON \ -DGDAL_BUILD_OPTIONAL_DRIVERSOFF \ -DGDAL_USE_INTERNAL_LIBSON \ -DGDAL_USE_EXTERNAL_LIBSOFF解释一下这几个关键项BUILD_SHARED_LIBSON必须生成DLL。OSGEarth在Windows下默认通过动态库加载GDAL如果你编成静态库后续链接和运行时的DLL部署会额外折腾。GDAL_USE_INTERNAL_LIBSON让GDAL优先使用它内部自带的第三方库版本。GDAL源码里内置了zlib、png、jpeg、tiff等一组第三方库源码开启这个开关能减少对外部环境的依赖降低编译失败的变量数量。GDAL_USE_EXTERNAL_LIBSOFF关闭对外部库的自动探测。如果不关闭CMake会尝试去系统里找一堆可能不存在或者版本不匹配的库结果不是报错就是编出个”意外产物”。3.2 编译与安装配置成功后cmake --build D:\3rdparty\build\gdal --config Release -j8 cmake --install D:\3rdparty\build\gdal这一步正常情况下不会出大问题。Windows下唯一要注意的是如果你的机器没有安装.NET或某些Python组件CMake可能会自动探测并启用相关绑定没必要的话可以在配置时追加-DGDAL_USE_PYTHONOFF -DBUILD_PYTHON_BINDINGSOFF -DBUILD_JAVA_BINDINGSOFF编完后验证一下D:\3rdparty\install\gdal\bin\gdalinfo.exe --version能正常输出GDAL版本号说明GDAL层OK。Gdal 3.12编译产物里bin目录应该包括gdalinfo.exe、ogrinfo.exe、gdal_translate.exe等一系列工具以及gdal.dll和一堆gdal_xxx.dll的驱动模块。4. OSG 3.6.5 编译别和预编译包较劲OSG编译的坑主要不在OSG自己而在它的插件体系和第三方库版本。OSG号称插件化架构场景里的图片、模型、字体加载全靠插件机制这意味着编译时必须把插件挂全否则就算OSG本体编好了跑起来加载不了数据一样抓瞎。4.1 源码与三方依赖去GitHub的osg-3.6.5标签下载源码包或者git clone -b OpenSceneGraph-3.6.5。然后下载对应VS版本的三方依赖包解压到D:\3rdparty\src\3rdparty目录。我这边是用VC2022的预编译包注意需要同时存在include、lib、bin三个子目录。4.2 CMake关键配置OSG的CMake配置项非常多我按重要程度拆开说。核心必勾项BUILD_OSG_PLUGINSON默认就是开着的注意不要关掉。插件就是OSG的生命线。BUILD_OSG_DEPRECATED_SYMBOLSOFF3.6.5里老API还有不少如果不兼容老代码建议关掉减少编译时间。OPENGL_PROFILEGL3或GL2这个要慎重。OSGEarth 3.7.2的REX引擎对OpenGL Core Profile支持比较好但如果你的显卡驱动不给力建议选GL2兼容性更好。我自己的开发机用的是GL3跑起来没问题。OSG_USE_QTOFF如果你不需要OSG内嵌到Qt窗口里先关掉省去Qt环境的头痛问题。后面需要时再单独编。与三方库相关的路径配置CMAKE_PREFIX_PATH设为D:\3rdparty\src\3rdpartyCMake会在该目录下找include/lib/bin。3RD_PARTY_INCLUDE_DIR和3RD_PARTY_LIB_DIR如果CMake没自动找到就手动指定到对应目录。需要注意ZLib的检查。OSG编译时会对ZLib做检查如果预编译三方包里ZLib是好用的CMake会自动找对。如果没找到后面编译osgDB时就会报zlib.h not found的错这时候别去改源码路径直接回头检查CMake配置里的ZLIB_INCLUDE_DIR。4.3 编译与安装OSG的编译时间比较长建议用多线程cmake --build D:\3rdparty\build\osg --config Release -j8 cmake --install D:\3rdparty\build\osg编译产物会放到D:\3rdparty\install\osg下bin目录里应该有osgviewer.exe、osgversion.exe、一堆osgPlugins-3.6.5的DLL。OSG的插件目录名一定要是osgPlugins-3.6.5这是OSG在运行时硬编码查找的目录不要自己改名。如果你把插件DLL和exe放一起OSG反而找不到它们。4.4 环境变量配置OSG运行时有三个环境变量很重要OSG_FILE_PATH用于指定默认数据路径。测试时可以指向你的示例模型目录比如D:\3rdparty\data。PATH需要把D:\3rdparty\install\osg\bin加到PATH里否则exe启动时找不到osg*.dll。OSG_NOTIFY_LEVEL建议设为WARN或INFO。遇到插件加载问题、模型读取失败时控制台输出的日志能帮大忙。默认是NOTICE经常把关键报错淹没。验证OSGosgviewer.exe --version osgversion.exe能看到版本号说明OSG本体编译OK。再用一个牛模型或者cow.osg测试一下osgviewer.exe cow.osg弹出一个窗口且能看到牛模型OSG就算真的可用了。5. OSGEarth 3.7.2 编译把上面两块拼起来OSGEarth编译是整个流程的重头戏也是最容易暴露隐藏问题的环节。它的CMake配置本质上是找依赖游戏CMake会去系统指定路径里找OSG、GDAL、curl、geos、sqlite3等库找到一个算一个找不到就报错退出。5.1 CMake配置中的路径传导我的做法是不挨个设置OSG_DIR、GDAL_DIR而是直接用CMAKE_PREFIX_PATH把所有库的安装目录根部传进去cmake -S D:\3rdparty\src\osgearth-3.7.2 -B D:\3rdparty\build\osgearth \ -DCMAKE_INSTALL_PREFIXD:\3rdparty\install\osgearth \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_PREFIX_PATHD:\3rdparty\install\gdal;D:\3rdparty\install\osg;D:\3rdparty\src\3rdparty;D:\3rdparty\install\otherCMake的find_package机制会在所有prefix路径下按include、lib、share/cmake等目录去寻找配置文件。OSG安装后会在D:\3rdparty\install\osg\lib\cmake下生成osgEarth相关的CMake配置文件GDAL也会在lib\cmake下生成GDALConfig.cmake只要路径指对了CMake就能自动完成发现。如果你用的是旧的CMake习惯手动设置OSG_DIR和GDAL_DIR也不是不行但容易踩一个坑CMake版本不同对XXX_DIR变量的后缀匹配规则不同有时你设置了变量但依然检测不到库。统一用CMAKE_PREFIX_PATH最省心。5.2 三个特别值得注意的依赖项curlOSGEarth访问在线影像、地形服务时需要curl。如果CMake找不到curl会提示Could NOT find CURL。这个依赖在vcpkg里很好装或者下载官方Windows二进制包解压后把路径也加入CMAKE_PREFIX_PATH。GEOSOSGEarth的空间运算功能依赖GEOS不编的话Feature相关功能会受限。GEOS官方提供了Windows预编译包同样把路径加进CMAKE_PREFIX_PATH。SQLite3OSGEarth的缓存和SpatialReference数据库需要sqlite3。OSG的预编译三方包里可能没有建议从sqlite官网拿预编译DLL同样放进prefix目录。这里介绍一个CMAKE_PREFIX_PATH小技巧CMake查找的顺序是按分号分隔依次查找所以把最可能缺失的库放在最前面提示信息能更快定位问题。如果你在配置时看到某个FindXXX.cmake报错先检查对应的安装目录是否在CMAKE_PREFIX_PATH里而不是急着去搜源码问题。5.3 Debug/Release混用问题MSVC最隐蔽的坑这个坑我专门拿出来说因为它出现的概率极高且报错信息莫名其妙。如果你用预编译的OSG三方依赖包Release编出了Release版OSG然后又把Debug版OSGEarth链接Release版GDALMSVC会在链接阶段报LNK2038 mismatch detected for RuntimeLibrary或者更诡异地在运行阶段崩溃。原因是MSVC把C/C运行库分成了/MDRelease动态、/MDdDebug动态、/MTRelease静态、/MTdDebug静态四种模式Debug和Release的库如果混用链接器会发现运行库不一致而拒绝。这个错误不会告诉你是哪个库的问题只会提示value mismatch。解决办法只有一个Debug链路的OSG、OSGEarth、GDAL全部用Debug编译Release链路的全部用Release编译。编译OSGEarth时如果你打算发布Debug版那么OSG、GDAL、curl、geos也必须是对应的Debug版。这也是为什么我在前面强调如果工程需要Debug版三方预编译包就别用了全程自己编。5.4 编译安装与验证上面配置完毕后cmake --build D:\3rdparty\build\osgearth --config Release -j8 cmake --install D:\3rdparty\build\osgearth装完后D:\3rdparty\install\osgearth\bin下会有osgearth_viewer.exe、osgearth_*等一堆工具以及osgEarth.dll和一堆osgPlugins相关的DLLOSGEarth也会生成自己的插件如osgdb_earth等。验证时先试一试用自带的earth文件打开osgearth_viewer.exe D:\3rdparty\data\simple.earth如果弹出三维地球窗口并加载出影像或地形说明OSGEarth与OSG、GDAL的对接已经通了。如果窗口黑屏先看控制台日志重点找Cant load plugin或OpenGL context字样的报错。6. 集成验证把三个库串起来跑通最小示例编译完不代表能用。实际项目里最容易卡住的是运行阶段因为三个库安装后各自有相对独立的bin、插件目录、数据目录必须在系统层面把它们聚合起来。6.1 合并运行路径我建议在系统环境变量里按如下方式配置变量名值PATH追加D:\3rdparty\install\gdal\bin、D:\3rdparty\install\osg\bin、D:\3rdparty\install\osgearth\bin、D:\3rdparty\install\other\binGDAL_DATAD:\3rdparty\install\gdal\share\gdalGDAL_DRIVER_PATH可为空默认GDAL会从自身路径加载驱动目录不设也行OSG_FILE_PATHD:\3rdparty\dataOSG_NOTIFY_LEVELINFO调试期GDAL_DATA一定要设。这个变量指向GDAL的数据共享目录里面包含gcs.csv、pcs.csv、datumshift等坐标参考系文件。不设置的话GDAL在涉及坐标系转换时经常静默出错OSGEarth在加载某些影像或矢量数据时可能完全不显示报错也很含糊——不设GDAL_DATA几乎是最难定位的问题之一。6.2 最小示例工程为了验证链接我写了一个最小控制台程序加载一个earth文件创建Viewer然后逐帧渲染。#include osgViewer/Viewer #include osg/Node #include osgDB/ReadFile #include osgEarth/MapNode #include osgEarth/Map #include osgEarth/EarthManipulator #include osgEarth/Viewpoint #include iostream int main(int argc, char** argv) { osg::ArgumentParser arguments(argc, argv); osgViewer::Viewer viewer(arguments); osg::ref_ptrosg::Node node osgDB::readRefNodeFile(simple.earth); if (!node) { std::cerr Failed to load earth file. std::endl; return -1; } viewer.setSceneData(node); return viewer.run(); }把这个示例项目用CMake编译时CMakeLists.txt里必须要正确传递依赖路径cmake_minimum_required(VERSION 3.20) project(OsgEarthDemo) find_package(OpenSceneGraph REQUIRED COMPONENTS osgDB osgUtil osgViewer osgGA osg) find_package(osgEarth REQUIRED) add_executable(OsgEarthDemo main.cpp) target_link_libraries(OsgEarthDemo ${OPENSCENEGRAPH_LIBRARIES} ${OSGEARTH_LIBRARIES})CMake配置时同样把prefix路径传入cmake -S . -B build \ -DCMAKE_PREFIX_PATHD:\3rdparty\install\gdal;D:\3rdparty\install\osg;D:\3rdparty\install\osgearth;D:\3rdparty\install\other链接通过、程序能弹窗整个编译链才算真正闭环。6.3 两个容易误判的运行时问题实际跑起来还会遇到画不出东西的情况。个人经验里最高频的两类第一类是插件加载失败日志里提示Warning: Could not find plugin to read objects from file xxx.earth。这类问题通常不是earth文件本身的错而是OSGEarth和OSG的插件目录没加载对。检查PATH里是否包含osgearth的bin目录以及bin目录下是否有osgdb_earth.dll。另一个常见原因是OSG和OSGEarth都往同一个osgPlugins-3.6.5目录里装插件安装时常出现覆盖冲突解决方法就是先装OSG再在同一路径下装OSGEarth或者反过来统一在同一个bin下。第二类是显卡驱动上下文问题报错Error: Unable to create OpenGL context。多半在远程桌面、虚拟机或者老旧显卡驱动上出现。临时解决可以设置环境变量OSG_GL_CONTEXT_DEBUGON看输出但根本办法还是更新显卡驱动。OSGEarth 3.7.2默认走REX引擎需要在OpenGL 3.3环境下运行如果显卡只支持2.1画面就会完全黑掉。7. 项目化编译把能跑变成好维护到第六步整套编译流程已经可以复现了。但如果要放进团队协作或者长期维护还值得多做一步——把整个编译过程固化称脚本或者配置文件避免下次换台机器或者换个人接手时装依赖装到怀疑人生。7.1 把CMAKE_PREFIX_PATH固化成变量每次都在命令行里敲一长串-DCMAKE_PREFIX_PATH...很容易出错。我习惯在项目根目录放一个env.bat把所有路径固化echo off set PREFIX_ROOTD:\3rdparty\install set PATH%PREFIX_ROOT%\gdal\bin;%PREFIX_ROOT%\osg\bin;%PREFIX_ROOT%\osgearth\bin;%PATH%配合CMake的时候在CMakeLists.txt里提供一个默认值if(NOT CMAKE_PREFIX_PATH) set(CMAKE_PREFIX_PATH D:/3rdparty/install/gdal D:/3rdparty/install/osg D:/3rdparty/install/osgearth D:/3rdparty/install/other ) endif()这样在VS里直接配置CMake工程不用手工传参打开就能编。团队里其他人拉代码后只要保证D:\3rdparty\install目录与脚本一致配置过程从半小时压缩到十分钟。7.2 保留一份依赖清单编译尘埃落定后强烈建议留一份依赖清单写明每个库的源码版本、CMake选项、修改过的参数、安装日期。我这边用Markdown维护例如库版本关键CMake选项备注GDAL3.12.0BUILD_SHARED_LIBSON, GDAL_USE_INTERNAL_LIBSON禁用Python/Java绑定OSG3.6.5OPENGL_PROFILEGL3, OSG_USE_QTOFF插件全开OSGEarth3.7.2CMAKE_PREFIX_PATH统一指installREX引擎这份清单的价值在后排人员接手、版本升级、排查诡异链接错误时体现得淋漓尽致。7.3 定期升级GDAL的注意点GDAL的版本更新节奏很快特别是3.10之后的小版本频繁。如果将来打算把GDAL升到更高版本建议注意两点一是GDAL的DLL导出符号和头文件ABI兼容性不做保证最好连带OSGEarth一起重编不要只替换DLL二是GDAL自身依赖的第三方库版本会变如果开GDAL_USE_INTERNAL_LIBSON问题不大但如果外部引入了一套zlib要再次检查版本匹配。这套组合的编译本质上就是一次CMake依赖管理的实操顺着CMAKE_PREFIX_PATH这个核心思路走GDAL、OSG、OSGEarth三个库无论怎么升级都能大概率顺畅编过。我刚折腾完时最深的体会是不要在网上找一遍适配所有环境的完美教程环境差异比代码差异重要得多多花二十分钟把环境变量和目录结构梳理清楚后面省下来的时间是以小时计的。如果这篇文章帮你少走了一段弯路那这个周末折腾得就值了。

相关新闻

最新新闻

Redis桌面客户端怎么选?主流工具盘点与实战指南

Redis桌面客户端怎么选?主流工具盘点与实战指南

搞开发的应该都有过这样的体验:Redis装好了,redis-cli敲得飞起,keys *、get xxx、info memory这些命令闭着眼睛都能打出来。但真到了排查线上问题时,满屏的字符串和哈希字段看得人头皮发麻,想快速确认某个key到底存了什…

2026/9/7 20:49:06
PSIM仿真相:无刷电机三相逆变U、V、W波形搭建与调试全攻略

PSIM仿真相:无刷电机三相逆变U、V、W波形搭建与调试全攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/7 20:49:06
Claude Code 4.5 Windows安装全攻略:Node.js与npm配置详解

Claude Code 4.5 Windows安装全攻略:Node.js与npm配置详解

Claude Code 4.5 在 Windows 上安装这件事,我一开始以为就是 npm install 一条命令的事,结果被 PowerShell 执行策略、Node 版本、终端乱码、路径空格来回折腾了几次,才算彻底理顺。这篇文章聚焦一件事:把 Claude Code 4.5 从零…

2026/9/7 20:49:06
汽车零配件企业MES系统落地指南:对接金蝶云星空的实战经验

汽车零配件企业MES系统落地指南:对接金蝶云星空的实战经验

做汽车零配件这些年,大大小小的系统也推进过好几套。如果让我选一个最难上的、最容易被车间骂声淹没的,MES一定排在前三。但真正用顺了之后,它也是车间管理里最离不开的一个系统。 很多人对MES的认知停留在“生产管理软件”这六个字上&#…

2026/9/7 20:49:06
基于Modbus协议的在线监控网关方案:从轮询机制到数据采集实践

基于Modbus协议的在线监控网关方案:从轮询机制到数据采集实践

先别急着谈技术选型,说说我当时为什么一定要做这个基于Modbus的在线监控网关方案。工厂改造那阵子,现场设备品牌杂得很,PLC有西门子的、台达的,仪表有七八种不同协议的,变频器更是国产进口混着来。你要是每个设备单独拉…

2026/9/7 20:49:06
Flink/Kafka/Netty生态中的Async HTTP Client为何无处不在?

Flink/Kafka/Netty生态中的Async HTTP Client为何无处不在?

如果你平时接触 Flink、Kafka 或者 Netty 相关的服务端代码,大概率会在某个依赖树里看到org.asynchttpclient这个包。很多人的第一反应是:这不就是一个 HTTP 客户端吗?但为什么 Flink 的异步 IO 文档拿它当默认示例,Kafka 周边的一…

2026/9/7 20:44:06