简介:这是Windows下采用MSYS2与MinGW64预先编译完成的GDAL 1.11.5开发包,专供Qt(MinGW版本)C++开发者使用。整个压缩包约70.71MB,共149个文件,其中包含63个头文件、2个静态库、22个exe工具,以及一批坐标系CSV、WKT和XML配置数据,覆盖了GDAL常用功能与数据格式支持。将bin目录加入系统环境变量,再在.pro文件里指定GDAL路径即可直接链接,免去在MinGW环境下从源码编译的麻烦。目前已有1514人学习下载。该包不仅带有可直接调用的运行库,还提供了gdal-config等辅助脚本和完整目录结构,方便用户按需查看和配置。针对Qt+MinGW中常见的程序异常结束问题,作者在配套博文中给出了具体排错思路,下载后遇到问题可对照解决,适合希望快速搭建GDAL开发环境的中高级C++开发者。 最近接了个内部老项目,后端服务要对接一套2015年前后构建的GIS中间件,接口里全是GDAL 1.x的API调用。开发机是Windows 10 64位,团队同事一开始直接在vscode的mingw64环境里把系统默认的GDAL(3.x)拉下来编译跑,结果一堆核心函数行为对不上——最典型的就是GDALOpen和OGRRegisterAll在3.x里的执行路径跟1.x完全不一样,平面坐标的读取结果也有细微偏差。项目卡了两天,最后决定一步到位:手工把GDAL 1.11.5用mingw64编译一遍,在Windows上生成独立的C++库。这篇文章就把整个过程完整记录下来,包括依赖版本、configure参数、编译坑和最终CMake集成方式,给同样被老库困住的朋友一条可以直接抄的路径。
1. 为什么在现代化环境里还要折腾GDAL 1.11.5
1.1 老项目的API兼容性需求
GDAL 1.x与2.x、3.x表面上是版本号差异,实际上是两代人。GDAL 1.11.5是1.x分支最后一个维护版本,2015年6月23日发布。它对应的API形态、头文件组织和数据结构与3.x有大量不兼容。最典型的是OGRFeature、GDALDataset这类对象的生命周期管理,在1.11里靠引用计数和GDALClose手工释放,3.x虽然保留了GDALClose,但内部所有权模型已经变了。还有GDALAllRegister在1.x会一次性注册所有驱动,3.x改成了按需注册,默认行为完全不同。
如果你的业务代码是十年前写的,直接用新版GDAL重新编译,轻则行为不一致,重则内存崩溃,这在GIS领域特别常见。不少金融机构、管网、测绘单位到现在还在用1.11,不是不想升级,是升级成本太高,动一条核心查询链路,牵扯的都是几十年积累的坐标转换和格式兼容逻辑。所以遇到老系统对接,老老实实把对应的老版本GDAL编出来,反而是最稳妥的解法。
1.2 为什么选mingw64而不是MSVC
在Windows上编译一个C++库,首先面对的就是工具链选择。GDAL官方对Windows主要提供的是MSVC的nmake方案(makefile.vc),如果团队用的是Visual Studio那当然没问题,但很多开源项目团队是vscode或CLion加CMake的组织方式,代码里大量使用GCC特性,整个项目工具链已经在mingw64上沉淀了两三年。在这种前提下单独为GDAL开一套MSVC工程,后续每次编译都要切环境,成本极高。
mingw64的优势在于它是纯GNU工具链,和MSYS2、Cygwin生态完全打通,configure脚本可以像在Linux上一样跑,依赖库也能直接用pacman装,整个编译流程不折腾。缺点就是GDAL官方对mingw的支持没那么精细,很多细节要自己处理,但这篇文章的价值就是把细节填平。如果你也处在“CMake + GCC + vscode”这套工作流里,选mingw64基本不用纠结。
2. 编译前的依赖准备(这一半的坑都在这里)
2.1 用MSYS2当大本营,all in one
GDAL属于那种看起来简单,实际依赖树很深的库。直接下载一个裸的mingw-w64工具链,你会发现后面所有依赖都装不齐。所以第一步是安装MSYS2,官方安装包装完,打开开始菜单里的“MSYS2 MinGW64”窗口,注意一定要选MinGW64这个,不是MSYS2 MSYS那个,两者的包体系和编译器前缀完全不同。
进到MinGW64窗口后,先更新包索引和工具链:
pacman -Syu pacman -S --needed base-devel mingw-w64-x86_64-toolchainmingw-w64-x86_64-toolchain会带gcc、g++、gdb、make等全套工具。注意MSYS2 MinGW64环境里的make是GNU make,可以直接用,不是Visual Studio那个nmake,也不是兼容用的mingw32-make。
2.2 最容易翻车的PROJ依赖版本
GDAL 1.11.5配套的PROJ版本是PROJ 4.x系列,4.8到4.9都可以。如果你直接用pacman -S mingw-w64-x86_64-proj,装出来大概率是PROJ 6以上甚至9.x。PROJ 6之后API发生了大改,最常见的是pj_init_plus直接消失,PJ_PROJ4结构体也变了,GDAL 1.11.5编译时会在ogrct.cpp这些文件里报一堆undefined reference,根本排不完。
正确的做法是手动编译一个旧版PROJ。到OSGeo/proj仓库找到4.9.3的tag,下载源码,在MSYS2 MinGW64窗口里执行:
curl -L -o proj-4.9.3.tar.gz https://download.osgeo.org/proj/proj-4.9.3.tar.gz tar xzf proj-4.9.3.tar.gz cd proj-4.9.3 ./configure --prefix=/c/gdaldeps make -j8 make install这里把PROJ装到/c/gdaldeps,也就是C:\gdaldeps,避免和MSYS2系统目录混在一起。为什么不用默认的/usr/local?因为后续GDAL也要指定前缀,把所有自编译依赖统一放一个目录,后面排查路径问题会非常省心。GEOS也一样,从GEOS 3.4.x源码编到/c/gdaldeps,避免和pacman里太新的GEOS冲突。
2.3 必装依赖清单与作用解析
GDAL的依赖库可以分为三档:必选、常用可选、完全可选,你编GDAL之前心里得有数。我列一份实操清单:
mingw-w64-x86_64-zlib:几乎每个格式都会用到,必装。mingw-w64-x86_64-libtiff:TIFF/GeoTIFF读写必装,GDAL最核心的栅格格式就是GeoTIFF。mingw-w64-x86_64-libpng、mingw-w64-x86_64-libjpeg-turbo:PNG和JPEG读写。mingw-w64-x86_64-geos:矢量空间运算,Union、Intersection那些。mingw-w64-x86_64-sqlite3:OGR SQLite驱动和GeoPackage支持。mingw-w64-x86_64-libcurl:WMS/WFS在线服务支持,用不到可以先去掉。mingw-w64-x86_64-netcdf、mingw-w64-x86_64-hdf5:科学数据集格式,看项目需求装。
对应的pacman安装命令:
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-geos mingw-w64-x86_64-sqlite3 \ mingw-w64-x86_64-libcurl装完检查一下/mingw64/include下有没有proj_api.h,如果有,确认版本是不是老的:
grep PJVERSION /mingw64/include/proj_api.h如果显示6.x以上,别指望用它,直接走自编译旧版PROJ的路子。依赖库在Windows下编译,最怕的就是库搜索路径混乱,MSYS2自带的库都在/mingw64下,而自编译的PROJ在/c/gdaldeps下,混合使用时要通过configure的--with参数明确告诉GDAL去哪找,不能指望链接器自己串门。
3. 从configure到make的完整编译过程
3.1 configure到底在配置什么
configure脚本是GDAL源码包自带的自动配置工具,作用是把依赖路径、编译参数、可选功能全部探测一遍,生成最终的Makefile。GDAL 1.11.5的configure参数不算多,但有几个必须显式指定,否则它默认去/usr/local找库,你的依赖如果装在别处就全歪了。
我实际用的命令是:
./configure --prefix=/c/gdallib \ --host=x86_64-w64-mingw32 \ --with-proj=/c/gdaldeps \ --with-geos=/c/gdaldeps/bin/geos-config \ --with-sqlite3=/mingw64 \ --with-libz=/mingw64 \ --with-libtiff=/mingw64 \ --with-libpng=/mingw64 \ --with-libjpeg=/mingw64 \ --with-curl=/mingw64 \ --with-expat=/mingw64 \ --without-python \ --without-java几个正在起作用的关键项:
--prefix=/c/gdallib:最终安装目录,GDAL头文件和库都会放这里。--host=x86_64-w64-mingw32:告诉configure目标平台是64位Windows。这个参数在MSYS2环境下通常能自动识别,但显式写出来更保险,可以避免configure检测到纯MSYS环境后误判。--with-proj=/c/gdaldeps:PROJ安装在C:\gdaldeps,这里直接指到前缀目录。--with-geos=/c/gdaldeps/bin/geos-config:geos-config是GEOS提供的一个脚本,输出编译参数,GDAL靠它定位GEOS。所以GEOS也要装到/c/gdaldeps下,否则它不会出现在/c/gdaldeps/bin。--without-python:Python绑定单独处理,不要让configure去探测SWIG版本,否则基本会卡住。
3.2 编译执行与产物落盘
configure跑完后,输出末尾会有大段摘要,把“GDAL is now configured”那段仔细看一遍,重点确认缺少哪些库,比如SQLITE support: no说明sqlite没找到,需要回头补。确认没有问题后开始编译:
make -j8-j8是并行编译的线程数,按CPU核数定,但别拉满。编译过程中输出会滚动很快,一般几分钟到十几分钟不等,取决于机器和可选功能的多少。如果某个文件报错,先记下报错文件名和行号,大部分是头文件路径不对或依赖库版本不匹配,往下看第5节的排查方法。
编译完成后:
make install安装完去/c/gdallib检查产物:
ls -la /c/gdallib/bin ls -la /c/gdallib/lib正常情况下,/c/gdallib/bin下会有gdalinfo.exe、ogrinfo.exe、gdal_translate.exe这些命令行工具,以及libgdal-1.dll(或类似名字,取决于libtool生成规则)。/c/gdallib/lib下会有libgdal.dll.a、libgdal.a、libgdal.la这些库文件,以及gdal_i.h、cpl_config.h等头文件。
注意:GDAL 1.11.5源码目录里有多个子目录存放头文件,比如
gcore/、ogr/、port/,安装时会合并到/c/gdallib/include。如果你发现某些头文件找不到,多半是安装目录没加全,检查有没有/c/gdallib/include/gdal_priv.h。
3.3 静态库还是动态库:一个容易被忽略的选择
GDAL 1.11.5在mingw64下默认构建的是动态库,生成libgdal-1.dll和导入库libgdal.dll.a。动态库的好处是最终程序体积小,多个调用方能共享同一份GDAL内存,但DLL必须能在运行时被找到,否则程序启动就报libgdal-1.dll not found。
如果你的目标是减少部署麻烦,希望所有依赖都打进exe,那可以在configure时增加--disable-shared --enable-static强制静态编译。代价是链接时所有依赖库的.a文件也必须齐全,而且GDAL本身很大,静态链接后exe会膨胀到几十兆。我的建议是默认用动态库,部署时把libgdal-1.dll和mingw的运行库(libgcc_s_seh-1.dll、libstdc++-6.dll、libwinpthread-1.dll)一起带到目标机器上,这几个运行库在/mingw64/bin下可以找到。
4. 编译后的验证与VS Code / CMake工程接入
4.1 用gdalinfo验证环境
编译成功只是开始,能不能被别人正常调用是另一回事。先在命令行验证:
export PATH=/c/gdallib/bin:$PATH gdalinfo --version正常会输出:
GDAL 1.11.5, released 2015/06/23再用一个小GeoTIFF测试读写:
gdalinfo your_test.tif如果输出能看到Coordinate System is:并正确打印投影参数,说明PROJ和GDAL的集成没问题。再测一下矢量驱动:
ogrinfo --formats | grep -i "ESRI Shapefile"能看到ESRI Shapefile驱动,说明OGR核心和shapefile驱动加载正常。这一步是整个环节里最爽的时刻,说明依赖、编译、链接全链路都通了。
4.2 CMake接入mingw64编译的GDAL
很多人在vscode加mingw64工程里卡在CMake找不到GDAL这一步。GDAL 1.11.5不提供标准的CMake config文件,CMake自带的FindGDAL模块实际去寻找的是gdal-config脚本,而GDAL 1.11在Windows安装时通常不生成这个脚本。所以推荐直接在CMakeLists.txt里写死路径,简单粗暴。
cmake_minimum_required(VERSION 3.16) project(gdal_test) set(GDAL_ROOT "C:/gdallib") include_directories(${GDAL_ROOT}/include) link_directories(${GDAL_ROOT}/lib) add_executable(test_gdal main.cpp) target_link_libraries(test_gdal gdal)注意target_link_libraries里写的是gdal,不用写全名,CMake在Windows上会找libgdal.dll.a或gdal.lib。
vscode侧面的c_cpp_properties.json里,includePath要加上C:/gdallib/include:
{ "configurations": [ { "name": "Win64-MinGW", "includePath": [ "${workspaceFolder}/**", "C:/gdallib/include" ], "defines": [], "compilerPath": "C:/msys64/mingw64/bin/g++.exe", "cStandard": "c17", "cppStandard": "c++17", "intelliSenseMode": "windows-gcc-x64" } ], "version": 4 }compilerPath要指向你的mingw64的g++,也就是MSYS2安装目录下的mingw64/bin/g++.exe。如果不配置,vscode可能默认找Windows SDK的MSVC,导致IntelliSense对GDAL头文件报一堆误报。
4.3 关于Python绑定,说说我的取舍
很多读者问GDAL编译出来后能不能直接给Python用。GDAL 1.11.5的Python绑定是依靠SWIG生成代码的,SWIG版本有个令人头疼的对应关系:GDAL 1.11要求SWIG 1.3.x,而现在MSYS2里的SWIG是4.x,生成的代码和1.11的C++接口根本不兼容。所以自己编译Python绑定的成本很高,我建议直接用pip install GDAL==1.11.5,配上早期Python 3环境或Python 2.7。如果项目必须用Python,也可以直接用conda建一个老环境装1.11.5,省心很多,C++这边老老实实用编译出的本地库就够了,两边不要混用同一个产物。
5. 常见问题与排查技巧实录
5.1 三个踩过才知道的坑
第一个坑是M_PI未声明。GDAL 1.11.5的老代码在很多地方直接用了M_PI,C++标准里这个宏本来就不保证存在,mingw的GCC默认也不会定义。编译到gdalwarp或ogr某些文件时会报'M_PI' was not declared in this scope。解决办法是编译时加上全局宏定义,在configure环节注入CFLAGS和CXXFLAGS:
export CFLAGS="-D_USE_MATH_DEFINES" export CXXFLAGS="-D_USE_MATH_DEFINES" ./configure ...Windows系统里_USE_MATH_DEFINES会强制让标准库把M_PI、M_PI_2这些常量暴露出来。
第二个坑是PROJ新旧版本错乱。编译过程中如果出现pj_init_plus、pj_transform相关的undefined reference,基本就是PROJ版本不对。GDAL 1.11源码里写死了老PROJ的符号,遇到新PROJ就崩。这个没有捷径,只能老老实实把PROJ 4.9.3编译到独立前缀,再用--with-proj指过去。别指望系统里两个PROJ共存能自动选对,configure的pkg-config优先搜系统路径,很容易选到新版本。
第三个坑是运行时DLL找不到。这个发生在目标机器或开发机换路径之后。GDAL本身是动态库,mingw的g++在链接时会把动态库依赖写入exe的导入表,运行时Windows会按PATH顺序搜DLL。如果只把libgdal-1.dll放在exe同目录,但它的依赖(比如libgcc_s_seh-1.dll、libstdc++-6.dll、libproj-0.dll、libsqlite3-0.dll)不在PATH里,照样启动失败。排查方法是用objdump -p your_exe.exe | grep "DLL Name"看看它依赖于哪些DLL,然后确保这些都在PATH或exe同目录下。
5.2 问题速查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| configure提示找不到proj | PROJ版本过新或路径不对 | 自编译PROJ 4.9.3并指定--with-proj=/c/gdaldeps |
编译报M_PI未声明 | mingw默认没定义M_PI | 加-D_USE_MATH_DEFINES |
链接报undefined reference,带pj_前缀 | PROJ版本不兼容 | 换回PROJ 4.x |
链接报undefined reference,带GEOS前缀 | GEOS版本不兼容 | 自编译GEOS 3.4.x |
运行时报libgdal-1.dll not found | DLL搜索路径没配置 | 把/c/gdallib/bin和/mingw64/bin加入PATH |
| IntelliSense对GDAL头文件报错 | vscode没配mingw编译器 | 在c_cpp_properties.json配置compilerPath为g++.exe |
| configure成功但Python绑定编不出 | SWIG版本不匹配 | 改用pip安装旧版GDAL |
这次编译前后折腾了快两天,真正消耗时间的不是make,而是定位PROJ版本和DLL搜索路径这两个隐性问题。编译老库就是这样——你眼前的东西往往不是真的问题,真正卡住你的藏在依赖链深处。如果让我重新来一次,我会先把所有老版本依赖(PROJ 4.9.3、GEOS 3.4.x)统一编译到独立目录,再编译GDAL,一个下午就能走完全程。另外建议各位先把安装好的C:\gdallib整个目录备份下来,下次换机器或者同事需要同样的环境时,直接把目录拷过去改下路径就能用,不用再从头折腾一遍编译。
本文还有配套的精品资源,点击获取