
简介本资源为GDAL地理空间数据处理库的全平台预编译版本集合面向GIS开发工程师、遥感应用开发者及跨平台地理信息系统项目实践者解决多端部署时GDAL库适配难、编译复杂、环境依赖冲突等核心问题。压缩包包含Windowswin64/win32、Linuxx86_64及Androidarm32等五大平台的完整二进制库辅以大量源码文件1138个cpp、1076个h、构建脚本213个gnumakefile、6个makefile、8个sh、文档463个html、32个txt、14个readme及测试配置70个gfs、52个csv总计2000个文件体积达395.71MB。已有1652人学习下载资源结构清晰支持快速集成至VS工程、Linux GCC项目或Android NDK开发环境可直接调用C API实现栅格/矢量读写、坐标投影转换、遥感影像处理等关键功能显著降低GIS底层开发门槛。 在GIS相关项目里摸爬滚打久了很难绕开GDAL这个名字。无论是读栅格、写矢量、做投影转换还是给影像做金字塔GDAL基本就是事实标准。但真正让它“劝退”不少人的不是函数怎么调用而是怎么把一个想要的版本、在想要的平台上、以想要的形态静态库/动态库给编译出来。尤其是当你同时要交付Windows桌面端、Linux服务端、Android移动端的版本库时这个工程的复杂度会瞬间拉满。我最近就把GDAL全平台版本库重新梳理了一遍覆盖win64、win32、linux、android含arm32和arm64五个目标统一了版本策略和构建脚本整理了一套可以直接复用的方案。这篇文章会把整个思路、构建细节和踩过的坑都写清楚希望能帮到正在或将要面对跨平台GDAL编译的朋友。1. 跨平台GDAL版本库的整体规划思路1.1 先想清楚你的平台矩阵是什么很多人一上来就执行configure、make完全没有先规划平台矩阵结果编到一半发现缺依赖或者编出来的库在另一个平台没法用。平台矩阵不是拍脑袋定的它直接决定了你的构建机器、工具链版本、依赖库来源和最终产物的打包方式。我这次的目标平台是五个win64、win32、linux、android32我这里是armeabi-v7a、androidarm64-v8a。为什么没有x86_64的Android模拟器因为实际业务里没有这个需求模拟器上的调试用arm64镜像加转译就够用了。你如果要做x86模拟器优化那个加一个target也不难但别一开始就摊大饼否则每个平台的依赖都要多维护一份。这里的核心问题是GDAL本身是C/C写的但它在几乎所有平台都依赖外部库比如proj投影库、geos几何运算、openssl加密/网络、curl网络请求、sqlite3矢量数据源。这些依赖在Linux上有系统包管理在Windows上就得靠vcpkg或者手动编译在Android上则必须用NDK交叉编译。所以平台矩阵的规划本质上也是依赖矩阵的规划。以openssl为例GDAL在很多数据源和网络访问场景下会用到它。而openssl在不同平台的编译方式差异非常大特别是Android平台openssl官方虽然支持NDK编译但OpenSSL 3.x和1.1.1在编译参数上有明显差异。我在这轮统一采用了openssl 1.1.1w因为它在嵌入式平台和旧版Android兼容性上更稳而且GDAL 3.x系列对它的支持也是最成熟的。1.2 版本选型主版本与补丁版本的取舍策略GDAL的版本演进非常快从3.4到3.6再到3.8每次都有一堆新功能和数据格式支持。但版本库不是越新越好而是越适合业务越好看。我这次做主版本线是GDAL 3.8.0补丁版本3.8.1、3.8.2以后如果有需要再补。选择3.8系列的核心原因有三个一是它对Proj 9.x的兼容性。GDAL和Proj的版本绑定关系非常严格Proj 9.2以上配GDAL 3.7以下是会出问题的。GDAL 3.8.0发布时对齐的Proj版本是9.3以上这个组合在性能和API稳定性上经过了较长时间验证。二是Java和.NET绑定的成熟度。你如果用过GDAL的Java绑定就会知道版本太新时SWIG生成的代码偶尔会有接口变化导致上层代码要跟着改。3.8.0的Java绑定和.NET绑定都已经比较稳定和很多现成的GIS框架兼容得很。三是社区反馈到位的补丁。3.8.0发布后的前两三个补丁版本官方修复了不少编译期和运行期的问题比如某些平台下GeoTIFF读取的边界情况。如果你的业务正在用3.8.0建议至少跟到3.8.2以上稳定性的提升是实实在在的。1.3 依赖管理openssl、proj、geos的顺序不能乱GDAL能编译通过一半的功夫在依赖上。依赖之间的耦合顺序非常讲究我列一下这次用的依赖版本组合openssl 1.1.1wproj 9.3.1geos 3.12.1curl 8.5.0sqlite3 3.45.0libpng 1.6.42、libjpeg-turbo 3.0.1、giflib 5.2.1编译顺序必须是openssl → sqlite3 → proj → geos → curl → 图片库 → GDAL。因为proj在编译时如果检测到sqlite3就会启用它的数据库支持不启用的话proj的很多功能直接瘸腿GDAL在编译时又会检查proj、geos、curl等是否可用并记录版本号。顺序反了轻则功能丢失重则链接时报一堆undefined reference。这里特别注意每个依赖库在跨平台编译时都要指定安装前缀--prefix并且所有平台统一用同一个路径结构比如/opt/gdal-deps。这样在交叉编译时头文件和库文件的查找路径是一致的不会因为路径漂移导致某一个平台编不过。2. Windows平台构建win32与win64并行处理2.1 环境准备MSVC还是MinGW这是个路线问题Windows上编译GDAL有两条路线MSVCVisual Studio和MinGW-w64。常规建议是MSVC尤其当你的产品最终要用Visual Studio编译并伴随.NET或C/CLI调用时MSVC产物是唯一稳妥的选择。MinGW编出来的东西虽然也能用但和MSVC的ABI不兼容混用会出现很隐蔽的崩溃问题。我这次直接两种都做了但主力是MSVC。Windows平台的GDAL编译官方提供了两个入口一是nmake的makefile.vc二是CMake。GDAL从3.5开始CMake的成熟度已经很高甚至官方在后续版本里都在往CMake迁移。我用的就是CMake Visual Studio 2022。win64方案用Visual Studio 2022的x64 Native Tools命令行配置CMake生成VS2022工程然后构建Release版本。win32方案注意必须用x86的Native Tools命令行且CMake的generator要指定Win32架构。一个容易忽略的点是Visual Studio 2022默认不再原生支持32位构建需要确保安装了“使用C的桌面开发”工作负载里的x86生成组件。2.2 CMake构建命令与关键参数win64和win32的CMake配置差异主要集中在架构和依赖库路径上我有一个基本的构建脚本骨架cmake -G Visual Studio 17 2022 -A x64 ^ -DCMAKE_BUILD_TYPERelease ^ -DCMAKE_PREFIX_PATHD:/gdal-deps/x64 ^ -DGDAL_USE_OPENSSLON ^ -DGDAL_USE_CURLON ^ -DGDAL_USE_GEOSON ^ -DGDAL_USE_PROJON ^ -DGDAL_BUILD_OPTIONAL_DRIVERSON ^ -DBUILD_JAVA_BINDINGSON ^ -DBUILD_CSHARP_BINDINGSON ^ ..关键参数我解释一下-A x64或-A Win32这是CMake在VS generator下指定架构的核心参数千万别漏。CMAKE_PREFIX_PATH指向依赖库的安装前缀GDAL会自动在这个目录下找proj、geos、openssl等。GDAL_BUILD_OPTIONAL_DRIVERSON这个参数决定是否编译可选的栅格/矢量驱动。默认OFF的话很多格式比如PostGIS、OpenFileGDB等就不会编译进去。但ON之后编译时间会显著变长需要权衡。BUILD_JAVA_BINDINGS和BUILD_CSHARP_BINDINGS如果要出Java或.NET的包装层这里必须打开。默认OFF。我建议在Windows上把GDAL的共享库gdal.dll和导入库gdal.lib分开管理。CMake默认会生成但你最好在install之后检查一下动态库在bin目录下静态库在lib目录下。实际发布时win64的gdal.dll大约在30MB到50MB之间具体取决于你启用了多少驱动。2.3 win32/win64产物的目录组织两个架构的产物不要混在一个目录里我的目录组织方式是dist/ win64/ bin/gdal.dll lib/gdal.lib include/gdal.h win32/ bin/gdal.dll lib/gdal.lib include/gdal.h虽然看起来只是x64和x86的区别但产物最好从编译期就不要混。因为后续给上层应用做集成时链接器会优先搜索指定的lib路径一旦放混了很容易把32位的lib链进64位的exe里然后整个程序启动即崩溃查起来非常头痛。2.4 一个需要注意的坑Windows下openssl的DLL命名openssl在Windows下编译出来后DLL名字可能是libssl-3-x64.dll这种带版本号的GDAL运行时依赖它。你把gdal.dll拷到目标机器上时很容易漏掉openssl的DLL。我建议在安装GDAL后用Dependencies工具或直接跑一个简单测试程序确认运行目录下所有DLL都齐了。这一步放在构建阶段做完能省下后面联调的大量时间。3. Linux平台构建从桌面到服务器3.1 桌面Linux的编译参数与依赖安装Linux是GDAL的“主场”编译相对顺畅但这不代表可以直接躺平。一个建议是不要直接使用发行版自带的GDAL包尤其不要在编译自己的GDAL时链接系统老的proj或geos版本。系统包版本不可控而且很可能和你的业务代码需要的版本对不上。我验证过的最稳路径是这样的以Ubuntu 22.04为例sudo apt update sudo apt install -y build-essential cmake ninja-build \ libssl-dev libcurl4-openssl-dev libsqlite3-dev \ libpng-dev libjpeg-dev libgif-dev libtiff-dev \ swig java-11-openjdk-headless系统包只装编译期依赖不要装libgdal-dev这个一定要记住。你后续手动编译的GDAL是独立安装到自定义前缀的不会和系统的冲突。然后同样用CMake配置但Linux下我习惯改用Ninja generator因为并行编译速度快很多cmake -G Ninja \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_INSTALL_PREFIX/opt/gdal/3.8.0/linux-x64 \ -DCMAKE_PREFIX_PATH/opt/gdal-deps/linux-x64 \ -DGDAL_USE_OPENSSLON \ -DGDAL_USE_CURLON \ -DGDAL_USE_GEOSON \ -DGDAL_USE_PROJON \ -DGDAL_BUILD_OPTIONAL_DRIVERSON \ -DBUILD_JAVA_BINDINGSON \ -DBUILD_CSHARP_BINDINGSOFF \ .. ninja -j$(nproc) ninja install3.2 动态库与静态库的选择场景Linux下有动态库和静态库两种交付形态这个选择不能拍脑袋。动态库libgdal.so体积小升级灵活是大多数场景的首选但你一旦把程序部署到一个没有GDAL的干净服务器上就得注意把libgdal.so.32这类依赖一起带上。Linux不自动搜索自定义路径的动态库你要么设置LD_LIBRARY_PATH要么把库拷贝到/usr/local/lib或者/etc/ld.so.conf.d下配置。静态库libgdal.a的优势是部署零依赖但体积极大。这次编出来的静态库大概有100多MB如果你的产物需要考虑分发带宽或运行时的加载速度这就要仔细掂量一下了。我个人的习惯是服务端提供动态库边缘嵌入式设备提供静态库。服务端反正有运维可以配好环境动态库更新也灵活嵌入式设备资源和网络带宽都有限静态库虽然有体积问题但省掉了大量so文件依赖部署成功率更高。3.3 用Linux常用命令快速校验版本库编译安装完成后务必做一次完整的验证。很多人装完GDAL就跑个gdalinfo --version就完事了但一个更好的习惯是同时检查它依赖的proj和geos版本# 查看GDAL版本及编译参数 gdalinfo --version # 查看GDAL编译时链接的proj版本 gdalsrsinfo --version # 动态库依赖检查 ldd /opt/gdal/3.8.0/linux-x64/lib/libgdal.so | grep -E proj|geos|ssl # 写一个Python脚本验证实际功能需要编译时打开Python绑定 python3 -c from osgeo import gdal; print(gdal.VersionInfo())这里ldd是Linux下最常用的依赖检查工具它能快速帮你判断出动态库是否能被正确装载。如果出现not found大概率是依赖库路径没生效。这个验证动作我在每个平台编译完都会做一遍成本低但价值极高。4. Android平台构建android32armeabi-v7a与arm644.1 NDK工具链的选择与配置Android平台的GDAL编译是这五个目标里最复杂的主要原因在于NDK和依赖库的交叉编译都需要单独配置。我用的是NDK r25c因为从r25开始官方把旧的工具链封装成了更简洁的toolchain.cmake和CMake集成得非常顺。先配置Android NDK的环境变量Mac/Linux下示例export ANDROID_NDK_HOME$HOME/Android/Sdk/ndk/25.2.9519653然后为每个ABI准备一个toolchain文件。这个文件其实就是CMake的交叉编译配置文件内容如下set(CMAKE_SYSTEM_NAME Android) set(CMAKE_SYSTEM_VERSION 21) set(CMAKE_ANDROID_ARCH_ABI arm64-v8a) # 或 armeabi-v7a set(CMAKE_ANDROID_NDK $ENV{ANDROID_NDK_HOME}) set(CMAKE_ANDROID_STL_TYPE c_shared)重点说三个参数CMAKE_SYSTEM_VERSION这是Android API Level不是ABI版本。我取21意味着Android 5.0及以上都能跑覆盖面很广。如果你只做新设备设到24、26也没问题但没必要。CMAKE_ANDROID_STL_TYPEC标准库类型。c_shared会让你的库依赖libc_shared.so安装包里必须带上c_static则会把标准库编进你的库体积大一些但省心。我一般用c_shared因为GDAL本身很大静态加上标准库会让.so文件膨胀得非常离谱。CMAKE_ANDROID_ARCH_ABI这个参数决定了你是编arm32还是arm64。armeabi-v7a和arm64-v8a需要各跑一次CMake配置不能混。4.2 依赖库的Android交叉编译顺序Android上编译GDAL依赖库的顺序和通用桌面平台一致openssl → sqlite3 → proj → geos → curl → GDAL但每个库都需要传入相同的toolchain文件和API Level。我在编译openssl时用的是它的独立脚本方式手动指定NDK工具链的路径。openssl 1.1.1w在Android下的编译大致是这样的思路export ANDROID_NDK_HOME$HOME/Android/Sdk/ndk/25.2.9519653 export PATH$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH ./Configure android-arm64 --prefix/opt/gdal-deps/android-arm64 \ -D__ANDROID_API__21 make -j$(nproc) make install注意这里的android-arm64是Configure的目标名。armeabi-v7a对应的是android-arm。如果你用clang的新工具链openssl官方脚本是直接支持的但一定要把__ANDROID_API__宏传进去否则编译可能会基于错误的最小版本。proj、geos、curl这三个库在Android下用CMake交叉编译即可注意两点一个是和GDAL一样要指定toolchain文件另一个是这几个库编译时可能自动去系统目录里找libm、libc等。Android的系统库路径和桌面Linux不同所以务必用CMAKE_FIND_ROOT_PATH把所有依赖搜索路径限制在NDK的sysroot内避免误链到宿主机的库。这里有一个非常经典的坑如果在proj编译时没有正确指定sqlite3的路径proj会把PROJ_DBproj.db数据库文件的编译期搜索路径指向宿主机目录。等到GDAL在手机上加载proj时会因为找不到proj.db直接初始化失败。解决方法是把proj的安装前缀和data目录路径明确配置并在运行时设置PROJ_LIB环境变量指向正确的data目录。4.3 Android Studio集成JNI与动态库打包Android平台编译GDAL的最终目的通常不是直接给Java调而是通过JNI封装底层能力。Android Studio里集成GDAL基本步骤是把编译好的libgdal.so、libproj.so、libgeos.so等放到app/src/main/jniLibs/armeabi-v7a和app/src/main/jniLibs/arm64-v8a目录下。在项目里写一个.cpp文件通过JNI调用GDAL C API再暴露给Java层调用。在CMakeLists.txt里通过target_link_libraries把libgdal.so链接进来。这里要特别提醒一点GDAL编译时如果启用了curl那么Android上的curl又依赖openssl和zlib。所以jniLibs目录下不只是GDAL一个so而是一整套依赖链。每次更新GDAL版本时这些依赖so的版本也必须同步更新不然就会出现运行时“UnsatisfiedLinkError”而且这个错误在Android Studio的日志里往往不会直接告诉你缺失的是哪一个so。一个稳妥的方案是在Java层做一次动态库加载顺序的诊断static { System.loadLibrary(c_shared); System.loadLibrary(ssl); System.loadLibrary(crypto); System.loadLibrary(sqlite3); System.loadLibrary(proj); System.loadLibrary(geos); System.loadLibrary(curl); System.loadLibrary(gdal); }顺序不能乱必须按照依赖关系从底层到上层加载。你如果把gdal放到最前面大概率会直接崩溃。对于android32armeabi-v7a和androidarm64-v8a两个ABI原生库要分开打包这是Android构建的基本常识。如果App需要同时支持32位和64位APK/AAB里必须同时包含两个ABI的so。如果你只编了arm64低端32位设备上安装时就会因为找不到库直接安装失败。5. 多语言绑定的版本适配5.1 Java绑定win/java/gdal 3.8.0安装教程网上经常能看到“win java gdal 3.8.0 安装教程”这种搜索词但大多数教程都停留在“下载gdal.jar然后System.loadLibrary”这个层面很少有教程把坑说清楚。我在这里总结一下我实践后的完整流程。Windows下要用Java绑定GDAL核心是三件事gdal.jarJava类库、gdalalljni.dllJNI动态库、gdal.dllGDAL主动态库。编译时如果CMake的BUILD_JAVA_BINDINGS设为ON会自动生成gdal.jar和对应的JNI库。安装时最常犯的错是把JNI库和主库路径搞混。Java层的System.loadLibrary(gdalalljni)会去java.library.path搜索而gdalalljni内部会依赖同目录下的gdal.dll。所以正确的配置是把gdal.dll、gdalalljni.dll以及所有依赖的openssl、proj、geos等DLL放在同一个目录。在Java启动参数里加上-Djava.library.path你的目录。或者在代码里显式指定路径System.load(绝对路径/gdalalljni.dll)。Linux下的Java绑定思路一样但动态库的后缀变成.so。而且Linux下更麻烦的是如果GDAL是手动编译到自定义目录的java.library.path还需要包含libgdal.so所在的目录并且设置LD_LIBRARY_PATH让JNI库能找到所有的依赖。否则启动时通常会报java.lang.UnsatisfiedLinkError: no gdalalljni in java.library.path。5.2 .NET绑定与dotnet publish的runtime裁剪问题.NET下使用GDAL通常有两种方式官方SWIG生成的C#绑定或者用GDAL的C API手动写P/Invoke。我在测试过3.8.0的C#绑定后发现用官方绑定 dotnet publish时会有个很扎心的问题runtime目录太大尤其是win64下DLL一大坨。其实这个问题的根子不是GDAL本身而是dotnet publish默认会把所有RID相关的运行库都复制出来再加上GDAL几十个依赖DLL整个发布包很容易超过200MB。解决方案是在csproj里指定固定的RuntimeIdentifierRID同时配置SelfContained和PublishTrimmed。一个实测有效的csproj关键配置片段PropertyGroup OutputTypeExe/OutputType TargetFrameworknet8.0/TargetFramework RuntimeIdentifierwin-x64/RuntimeIdentifier SelfContainedtrue/SelfContained PublishSingleFiletrue/PublishSingleFile PublishTrimmedfalse/PublishTrimmed /PropertyGroup这里PublishTrimmed我直接设了false。因为GDAL的C#绑定是通过SWIG生成的内部有大量反射和动态类型操作裁剪器无法安全分析开了trim后经常会出现运行时TypeNotFound或方法找不到的问题。裁剪省下的那点体积远没有稳定性和可预测性重要。另外单文件发布时PublishSingleFileGDAL的native DLL默认会解压到临时目录。如果需要把gdal的DLL也打包进单文件得注意在csproj里把相关DLL设为IncludeAllContentForSelfExtract否则程序在别的机器上跑会因为找不到gdal.dll而报错。这是我踩过的一个坑差点就要在用户机器上现场排障了。6. 版本库组织、校验与常见问题速查6.1 版本库目录结构设计版本库这东西最怕的是“能用就行”的心态。等到交付的时候你会发现如果没有一套清晰的目录结构连自己都找不到哪个库对应哪个平台哪个版本。我这次最终整理的结构是gdal-releases/ 3.8.0/ win64/ bin/ include/ lib/ java/ nuget/ win32/ bin/ include/ lib/ linux-x64/ lib/ include/ bin/ android-arm32/ lib/ include/ android-arm64/ lib/ include/ 3.6.2/ ...在版本库根目录放一个README.md把每个平台的构建日期、工具链版本、依赖库版本、已知问题都写清楚。可能有人觉得这是多此一举但当你三个月后回来看这批产物或者团队其他成员接手时这份文档能救命的。尤其是版本库一旦堆积多个版本没有说明文档的话最后会陷入“新版本编不出来旧版本不知道能不能用”的窘境。6.2 产物校验SHA256与功能冒烟测试构建完成的版本库不能直接发布一定要做两层校验第一层是文件完整性校验。给每个平台的压缩包生成SHA256校验值比如sha256sum gdal-3.8.0-win64.zip gdal-3.8.0-win64.zip.sha256第二层是功能冒烟测试。每个平台要跑一个最小功能集至少包括打开一个GeoTIFF并读取大小栅格读取读取一个GeoJSON文件矢量读取执行一次坐标转换Proj集成验证执行一次WGS84到Web Mercator的转换Proj.db加载验证Android平台因为不方便直接跑命令行我通常是在App层写一个JNI测试方法把上面三个操作封装进去在测试机上跑一遍。这一步做完了版本库才敢正式标记为release。6.3 常见问题与排查技巧实录这里把我这次跨平台编译中遇到的高频问题整理成一张速查表基本覆盖了大多数人会踩的坑问题现象可能原因解决办法编译GDAL时提示找不到proj头文件CMAKE_PREFIX_PATH未指向proj安装前缀正确设置依赖路径确保proj、geos在同一前缀下链接时报大量undefined reference toproj_*GDAL链接的是老版本proj或proj自身编译有问题检查proj版本确保用Proj 9.x并重新编译GDAL运行时找不到libssl.soopenssl安装路径未加入链接或运行路径编译时指定rpath或运行时设置LD_LIBRARY_PATHWindows下Java绑定提示找不到gdalalljnijava.library.path不包含JNI库目录显式设置java.library.path或在代码里load绝对路径Android NDK编译openssl报错API Level宏未设置或工具链路径错误确保Configure传入-D__ANDROID_API__21Android运行时初始化GDAL崩溃提示proj.db找不到proj的data目录路径不对设置PROJ_LIB环境变量指向包含proj.db的目录dotnet publish后运行找不到gdal.dll是单文件发布时native DLL未解压配置IncludeAllContentForSelfExtract或关闭SingleFileGDAL版本库目录混乱找不到对应产物缺乏目录规范和README按平台版本分层组织写清记录我再补充一个容易被忽略的细节Windows下如果同时安装了多个版本的GDAL环境变量PATH里出现的顺序会决定你调用的到底是哪个版本。运行gdalinfo --version前先where gdalinfo看一眼它的实际路径别在PATH混乱的环境里排查半天才发现自己调的根本不是刚编译的那个版本。6.4 关于版本库后续维护的个人体会版本库构建不是一次性工程而是长线维护的基建设施。根据我的经验每两到三个月跟着官方更新一次主版本或补丁版本是合理的节奏。但切忌盲目跟最新版一定要先在win64和linux-x64这两个最常用的平台上做全量测试确认没有破坏性变化后再扩展到你所有的平台矩阵。一个小技巧是把每个平台的构建脚本固化下来放到版本控制里。这样以后升级版本时只需要改版本号和依赖库路径剩下的流程都是可重复的。构建脚本即使写得不够优雅也比只存在某个人的命令行历史里要好一万倍。我自己就经历过一次重装系统后某些依赖库的编译参数再也回忆不起来的窘境从那以后每个构建步骤都必须有可回溯的脚本记录。最后再分享一个切身建议做跨平台GDAL版本库最忌讳的就是想一口气把所有平台一次搞定。老实说我这次也是先解决win64再逐步扩展到win32、linux-x64最后才碰Android。每做完一个平台就把脚本和文档沉淀好再进入下一个。这听起来慢但实际总用时反而是最短的。一个个平台啃下来比五个平台一起翻车再回头一个个排查要高效得多。本文还有配套的精品资源点击获取