简介:基于MSYS2与MinGW64编译完成的GDAL 1.11.5开发包,供Qt(MinGW版)环境下的C++开发者直接使用,解决GIS工程中GDAL库编译繁琐的问题。压缩包共149个文件,约70.71MB,以头文件、静态链接库、可执行工具和坐标参数CSV为主:头文件与静态库用于Qt项目链接调用,CSV提供投影、基准面与椭球参数,exe支持命令行格式转换。包内另有dll、ini等配套文件,解压后将bin目录加入环境变量,并在.pro中配置include和lib路径即可接入,若程序异常退出可参考作者排错博文快速定位。目前已有1514人学习下载,适合需要快速集成GDAL地理数据处理能力的MinGW64使用者。 说实话,如果只是想在Windows上用GDAL处理数据,我完全不建议去折腾编译——pip install gdal或者直接拉一个OSGeo4W安装包,几分钟就能开干。但如果你遇到的是下面这些场景:老项目锁定在GDAL 1.x系列、Qt用了MinGW工具链导致MSVC库没法混用、或者需要给一个叫libgdal-1.dll的旧库做兼容性封装,那"mingw64编译的GDAL 1.11.5"几乎就是唯一解。
GDAL 1.11.5是1.x系列的收官版本,在2016年底发布之后,整个1.x分支就停更了。按理说这种老版本早该被2.x、3.x替代,但地理空间领域的老代码生命力超出想象。我自己就接过一个维护需求:对方的GIS平台从32位迁移到64位,原来的GDAL预编译包是x86的,一连串依赖全部作废,最后只能自己动手在mingw64环境下从源码完整编一套。这篇就顺着这条线,把整个过程的决策逻辑、编译流程、踩坑点和集成方法写清楚,给后面要干同样事的人省点时间。
1. 为什么要折腾GDAL 1.11.5这种"老古董"
1.1 GDAL 1.11.5的特殊定位
GDAL 1.x和现在主流的2.x、3.x,在很多核心API上并不是无缝兼容的。1.11.5的代码主体是C++98风格,很多老项目里大量使用GDALOpen这种C接口配合C++封装来做二次开发,函数签名、错误处理、甚至数据模型都和后来的版本有明显差异。
尤其要注意的是,2.x引入的GDALOpenEx、统一栅格/矢量API,以及3.x对多线程模型的强化,让老代码在升级时不是改两个函数名那么简单。很多生产系统里基于1.x做的格式插件、内存数据管理逻辑,换到新版本后行为直接变了。所以一些对稳定性要求极高、又不想投入人力做迁移测试的团队,宁可在新环境里继续用1.11.5,也不愿意冒升级风险。
1.2 什么场景会把人逼到源码编译这一步
我自己遇到过的真实需求有几类,你可以对号入座:
- 老项目的构建环境从32位迁移到64位,原来下载的预编译GDAL只有x86版,或者x64版对应的依赖库版本和项目不匹配。
- 项目用了MinGW分支的Qt做桌面端开发,GIS核心模块需要链接GDAL。这时候MSVC编译的GDAL就非常尴尬,因为GCC和MSVC的导入库、运行时库、异常处理模型都不一致,硬链接的结果通常是编译报错,或者编译过了运行起来出诡异崩溃。
- 第三方库或插件明确依赖GDAL 1.11.5的导出符号和ABI,比如某些老版本的QGIS插件、收费GIS模块。
- 自己维护的发行套件里捆绑了特定版本的GDAL,为了保持所有环境行为一致,不允许随便换版本。
这一类需求基本都能在社区里搜到同类提问,结论都是一样的:用mingw64自己编,而不是找现成包。
1.3 为什么选择mingw64而不是MSVC的nmake方案
GDAL官方在Windows平台上的构建方案,最早是给MSVC准备的,源码目录里就有nmake.opt和说明文档。但GDAL 1.x整体构建体系是Unix风格:configure脚本、Makefile、gcc/g++这一整套。用MSVC去编也不是不行,但要额外处理很多环境变量和外部依赖,而且最终产物是.lib导入库,跟GCC系工具链基本绝缘。
mingw64则完全踩在GCC生态上:生成的libgdal.dll.a导入库可以直接让MinGW的GCC用,Qt的MinGW版本、Code::Blocks自带的编译器、MSYS2里的各种开源库都能无缝衔接。说白了,选择mingw64不是因为它比MSVC更好,而是因为你的下游工具链是GCC系,GDAL必须用同一套编译器来编译,这是最容易被忽略的一环。
2. 搭建mingw64环境:依赖库选型决定后面的坑
2.1 MSYS2与mingw64工具链
在Windows上获得mingw64工具链,最省事的方式是安装MSYS2。安装包从官网下载,默认装到C:\msys64。装完后不要直接用Windows的cmd去编译,GDAL 1.x的configure是shell脚本,需要在MSYS2提供的MinGW64环境里运行。
打开"MSYS2 MinGW x64"终端,先做一轮更新和工具链安装:
pacman -Syu pacman -S --needed base-devel mingw-w64-x86_64-toolchainbase-devel会带来patch、make等基础工具,mingw-w64-x86_64-toolchain则是完整的GCC工具链。注意必须是在MinGW64终端里,因为只有这个终端的PATH默认包含了/mingw64/bin,configure脚本才能顺利找到gcc和make。
2.2 依赖库:哪些必须、哪些可以砍
编译GDAL之前,最难的不是主程序编译,而是决定依赖库怎么配。依赖库选型直接决定你后面要踩多少坑,我给你一个实际测试过的最小配置参考:
| 依赖库 | 是否必须 | 作用 | 备注 |
|---|---|---|---|
| zlib | 必须 | TIFF/PNG等格式的压缩数据支持 | 建议用pacman装mingw64版本 |
| libtiff | 强烈建议 | GeoTIFF读写核心 | 没有它GDAL的栅格能力直接瘫痪 |
| libpng | 建议 | PNG格式支持 | 处理遥感图像时很常用 |
| libjpeg-turbo | 建议 | JPEG格式支持 | 同上 |
| proj | 视需求 | 坐标投影转换 | GDAL 1.11.5需要老版本proj 4.9.x,新版proj没有proj_api.h,这个是最大的坑 |
| geos | 可选 | 空间拓扑运算 | 不需要OpenGIS几何运算就关闭 |
| curl | 可选 | WMS/WCS等远程数据源 | 配置麻烦,新项目基本用不上 |
| sqlite3 | 可选 | GPKG等格式支持 | 不需要可以关 |
安装常用依赖库的命令:
pacman -S mingw-w64-x86_64-zlib \ mingw-w64-x86_64-libtiff \ mingw-w64-x86_64-libpng \ mingw-w64-x86_64-libjpeg-turbo \ mingw-w64-x86_64-expat这里有一个必须提前知道的常识:所有依赖库都必须用mingw64版本,不能用MSVC编译出来的版本。MSVC的.lib导入库在GCC面前就是一堆无法解析的符号,就算把DLL硬塞给编译器,也会在链接阶段报出漫山遍野的undefined reference。
2.3 源码包的正确获取方式
GDAL 1.11.5源码从官网历史版本目录就能拿到,文件名是gdal-1.11.5.tar.gz,大概几十MB,解压到任意工作目录,比如/c/src/gdal-1.11.5。
我的建议是解压到C:\src这种短路径下,尽量别放在C:\Program Files或带中文的目录里。GDAL 1.x的configure脚本对路径里的空格特别敏感,轻则检查不到依赖库,重则直接生成错误的Makefile,这类问题排查起来非常折磨人。
3. configure与make:GDAL 1.11.5核心编译流程
3.1 理解老的构建系统逻辑
GDAL 1.x的源码根目录里,你会看到两个体系并存:nmake.opt和nmakefile是给MSVC用的,configure和GNUmakefile则是给Unix/MinGW环境用的。mingw64走的完全是后者。
configure脚本会做环境探测,检查系统架构、编译器、依赖库头文件和库文件位置,把结果写入生成的GDALmake.opt和cpl_config.h。整个流程一旦出错,不要急着重新跑,先把最新报错信息定位到具体是哪个依赖检查环节失败,这比无限重试有用得多。
3.2 configure配置项:每个参数的实际含义
我实际使用的configure命令大致如下,拆开讲解:
cd /c/src/gdal-1.11.5 ./configure --prefix=/c/gdal-win64 \ --with-curl=no \ --with-geos=no \ --with-proj=/c/proj-4.9.3-win64 \ --with-python=no \ --without-libtool--prefix=/c/gdal-win64:安装路径,根据前面说的避开空格原则设置。--with-curl=no:明确关闭远程数据源驱动,避免configure去系统里反复查找curl库。如果你确实需要WMS等远程服务,就另外用pacman装上mingw-w64-x86_64-curl,再改成--with-curl=yes。--with-geos=no:没有安装GEOS就关掉。GDAL 1.x对GEOS的依赖不只是头文件,还涉及OGR几何函数的运行时交互,没有把握不要开。--with-proj=/c/proj-4.9.3-win64:这里指向的是你额外编译安装的PROJ 4.9.x目录。如果你不需要坐标转换,可以改成--with-proj=no,但GIS项目基本绕不开投影,我建议还是老老实实把老proj编出来。--with-python=no:关掉Python绑定,因为我们只需要C/C++库。OpenGDA官方对Python绑定的依赖比较啰嗦,开了反而容易因为distutils版本问题卡住。--without-libtool:GDAL 1.x默认有可能尝试走libtool构建路径,在MinGW环境下有时会生成动态库失败。不用libtool可以少一层麻烦,不过也可能导致产物只有静态库,具体看你需要的链接方式。
3.3 make、安装与产物验证
configure通过后,直接编译:
make -j4-j4是四线程并行,新手不建议给太高,因为如果某个编译单元报错,多线程的报错输出会混在一起,很难定位。等第一次编译成功之后,再考虑并行加速。
整个编译时间取决于机器性能,老机器可能二十分钟,新机器几分钟就能跑完。编译完成后执行:
make install安装后的目录结构大致是这样:
include/:gdal.h、gdal_priv.h、ogr_api.h、cpl_conv.h等头文件。lib/:libgdal.a静态库和libgdal.dll.a导入库。bin/:gdalinfo.exe、gdal_translate.exe、ogrinfo.exe等命令行工具,以及GDAL主动态库和依赖库。
验证一下基本功能:
/c/gdal-win64/bin/gdalinfo --version /c/gdal-win64/bin/gdalinfo --formats只要能看到GDAL 1.11.5, released 2016/...和一大票格式驱动列表,核心编译就算完成了。
4. 编译中高频踩坑:proj头文件、混用产物、gcc版本
4.1 proj 6.0以上移除了proj_api.h,GDAL 1.11.5直接编译失败
这是整个GDAL 1.x在mingw64下编译遇到最多的问题。PROJ库在6.0.0版本把老式的proj_api.h头文件和pj_init这套API全部移除了,只保留基于PROJ类和proj.h的新接口。
GDAL 1.11.5的代码里,凡是用到坐标投影的模块都依赖proj_api.h。如果你从MSYS2的源直接安装新版proj,configure阶段也许能检测到libproj库,但编译到对应文件时会直接报:
fatal error: proj_api.h: No such file or directory解决办法有两个:
- 推荐:下载PROJ 4.9.3源码,用同样的mingw64工具链编译并安装到独立目录,比如
/c/proj-4.9.3-win64,然后传给GDAL的--with-proj参数。 - 省事:
--with-proj=no,牺牲所有投影转换能力。
如果你做的是正儿八经的GIS开发,我强烈建议别在图省事之后后悔。坐标转换在GDAL里牵扯太广,很多格式驱动写进元数据时也会调用投影接口,关掉proj会损失大量功能。
4.2 依赖库混用MSVC产物,引发的连锁反应
有人会想,proj库我直接找一个MSVC编译好的DLL来凑合用,反正都是Windows。这个想法我劝你趁早打消。
MSVC和MinGW的导入库格式不同,pe导出符号机制也存在差异。MinGW的gcc链接器看到MSVC生成的.lib,通常会报:
undefined reference to `__imp_pj_init'这种以__imp_开头的未定义符号,就是GCC无法理解MSVC导入库的典型表现。就算个别库用dlltool能把DLL转成.a导入库,ABI层面的C语言结构体对齐、__cdecl调用约定等细节也容易埋雷。实践原则只有一条:GDAL的每一个依赖库都必须用mingw64编译,不要混用任何MSVC产物。
4.3 过新的gcc版本对老代码不友好
MSYS2仓库里的mingw64工具链更新速度很快,如果你装到了gcc 12甚至更高的版本,编译GDAL 1.11.5时可能会碰到老代码在严格编译器下报错的情况。常见症状是某些默认警告被当成错误,比如-Werror开启后,老代码里的类型转换或未使用参数直接中断编译。
遇到这种情况,可以在configure时人为放宽编译选项:
./configure --prefix=/c/gdal-win64 \ CFLAGS="-O2 -Wno-error" \ CXXFLAGS="-O2 -Wno-error" \ --with-curl=no \ --with-proj=/c/proj-4.9.3-win64如果已经编到一半报错,不建议盲目加-fpermissive,那是最后的逃生手段。更理性的做法是回去装一个gcc 9或10的旧版本,确保工具链和源码属于同一个时代。以我给几个项目搭环境的经验看,gcc 10在大多数情况下都能顺利编过1.11.5,gcc 12开始才需要额外处理。
4.4 路径、杀毒软件和其他隐蔽问题
再补充几个经常把人逼疯的细节:
- 安装路径和源码路径都不能有空格,
C:\Program Files这种目录是configure脚本的重灾区。 - Windows自带的杀毒软件有可能在生成大量DLL时误报,建议把MSYS2目录、源码目录、安装目录都加入白名单。
- 不要在Windows cmd里直接敲
./configure,那不是cmd能解析的脚本,必须在MSYS2 MinGW64终端里运行。 - 如果你的依赖库是用pacman装在
/mingw64下的,configure通常能自动找到;如果是自己编译安装到自定义目录,最好用--with-xxx=/路径明确指定,否则configure检查通过但实际编译时找不到头文件的情况也会出现。
5. 编译产物集成:CMake链接、动态库部署与实际测试
5.1 先做一轮冒烟测试
编译安装完成后,先用命令行工具做基础验证。找一张真实的GeoTIFF测试一下:
export PATH=/c/gdal-win64/bin:$PATH gdalinfo /path/to/your/test.tif能正确输出影像大小、波段数、投影信息,就说明GDAL核心驱动工作正常。ogrinfo再测一下矢量格式,比如读一个ESRI Shapefile,确认OGR模块也没问题。
测试阶段不要急着用CSV之类的简单格式,能覆盖GeoTIFF和Shapefile这种基础格式就足够暴露大多数问题。
5.2 在CMake工程中集成GDAL
GDAL 1.11.5本身没有内建CMake config文件,所以find_package(GDAL)依赖CMake自带的FindGDAL模块。这个模块老版本的习惯是优先找gdal-config程序。因此在CMake之前,需要把C:\gdal-win64\bin加入PATH,或者设置环境变量GDAL_ROOT,让CMake能找到对应的可执行文件。
一个常规的CMake集成写法:
find_package(GDAL REQUIRED) include_directories(${GDAL_INCLUDE_DIR}) target_link_libraries(myapp PRIVATE ${GDAL_LIBRARY})如果find_package还是找不到,就直接手动指定路径:
set(GDAL_INCLUDE_DIR "C:/gdal-win64/include") set(GDAL_LIBRARY "C:/gdal-win64/lib/libgdal.dll.a")需要注意的是,mingw下的GDAL导入库是libgdal.dll.a,不是MSVC习惯的gdal_i.lib。如果你的构建脚本里写的-lgdal,GCC会自动找到libgdal.dll.a或libgdal.a,不需要额外改库名。
5.3 写一个最小示例验证链接
写一个读取栅格影像基本信息的C++程序,验证整条编译链是否通畅:
#include "gdal_priv.h" #include <cstdio> int main() { GDALAllRegister(); GDALDataset* ds = static_cast<GDALDataset*>( GDALOpen("C:/data/test.tif", GA_ReadOnly)); if (ds) { std::printf("size: %dx%d, bands: %d\n", ds->GetRasterXSize(), ds->GetRasterYSize(), ds->GetRasterCount()); GDALClose(ds); } else { std::printf("open failed\n"); } return 0; }编译命令:
g++ -o read_img.exe read_img.cpp \ -I C:/gdal-win64/include \ -L C:/gdal-win64/lib -lgdal运行前,确保C:\gdal-win64\bin在PATH里,或者把GDAL主动态库和它依赖的proj、tiff等DLL全部拷到exe所在目录。如果运行时提示找不到DLL,先不要怀疑代码,直接在命令行里跑where gdal111.dll看路径是否可达。
我个人在实际排查中最常用也最有效的工具是objdump -p read_img.exe | grep "DLL Name",一条命令就能列出程序依赖的动态库列表,哪个缺失一目了然。
这套编译流程走完,再回头看整个过程,最花时间的其实不是GDAL本身的编译,而是把proj固定在4.9.x这个老版本上,并且确保所有依赖库统一用mingw64编译。只要你记住这个顺序:先统一工具链,再解决依赖库,最后回来编主库,基本能少走一大半弯路。
本文还有配套的精品资源,点击获取