ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

GDAL源码编译实战:精准控制地理空间库的功能与依赖

GDAL源码编译实战:精准控制地理空间库的功能与依赖

1. 为什么非得自己编译GDAL?系统包管理器不是更省事?

“Linux系统编译安装GDAL库”——这行字刚出现在终端命令行里,很多刚接触地理信息处理的朋友第一反应是:apt install gdal-bin 不就完了吗?pip install gdal 不也一行搞定?确实,Ubuntu/Debian 下sudo apt install libgdal-dev能快速装上头文件和链接库,CentOS/RHEL 上dnf install gdal-devel也能凑合用。但我在某高校遥感实验室带学生做高光谱影像融合项目时,连续踩了三次坑,才彻底明白:GDAL不是普通库,它是地理空间数据的“操作系统内核”,版本、编译选项、依赖链的微小偏差,会直接导致整个数据处理流水线在关键节点静默崩溃。

举个最典型的例子:某次学生用apt install libgdal-dev(Ubuntu 22.04 默认源)装的 GDAL 3.4.1,调用gdal_translate -of GTiff -co COMPRESS=LZW处理一幅 8GB 的 Sentinel-2 L2A 产品时,程序不报错,但生成的 TIFF 文件打开后全是黑块。查日志发现libtiff版本太老(4.3.0),不支持 LZW 压缩的某些新标志位;而系统源里的 GDAL 是用旧版libtiff编译的,链接时根本没启用 LZW 支持——gdalinfo --formats | grep -i tiff输出里压根没有LZW字样。你敲命令时以为功能存在,实际运行时它被编译期硬生生裁掉了。

再比如,某公司做三维实景建模,需要 GDAL 启用OpenEXR支持来读取摄影测量生成的高动态范围深度图。但主流发行版的预编译包默认禁用 OpenEXR(因为依赖复杂、编译时间长),你apt install装上的 GDAL 根本不认识.exr文件。gdalinfo input.exr直接返回ERROR 4: 'input.exr' not recognized as a supported file format.——不是路径错了,是这个格式压根没被编译进去。

还有更隐蔽的:Python 的osgeo.gdal模块,如果用pip install gdal安装,它会尝试匹配当前系统 Python 的 ABI 版本。但 pip 包通常只提供 x86_64 架构的 wheel,如果你在 ARM64 服务器(比如树莓派 5 或 AWS Graviton 实例)上跑,pip 安装会失败或降级到源码编译,而 pip 自带的编译脚本又常忽略--with-armadillo或--with-curl等关键开关,导致后续调用gdal.Warp()进行重投影时因缺少 PROJ 库的完整坐标系数据库而返回错误的经纬度偏移。

这些都不是 bug,而是预编译二进制包在“通用性”和“功能性”之间做的必然妥协。发行版维护者必须保证包能在最广泛的硬件和最小的依赖集上运行,所以会关闭大量可选特性;而你的项目需求是具体的、苛刻的、不可妥协的——它要求 GDAL 必须支持 HDF5 的并行 I/O、必须链接最新版 GEOS 以保证矢量叠加的拓扑精度、必须启用 SQLite3 的 FTS5 全文检索来加速属性表查询。这些,只有亲手控制./configure的每一个参数,才能确保。

所以,“编译安装”从来不是为了炫技,而是为了把控制权从包管理器手里夺回来。当你在./configure命令里敲下--with-hdf5=/usr/local/hdf5 --with-proj=/opt/proj-9.3.1 --with-spatialite=yes的那一刻,你不是在执行一条命令,你是在给 GDAL 铸造一把专属钥匙——这把钥匙,只为你手头那个正在跑的、有具体输入输出、有明确性能指标的项目服务。

提示:判断是否必须编译的黄金法则——打开终端,执行gdal-config --version && gdal-config --libs && gdal-config --includes。如果输出的版本号低于你项目文档要求的最低版本(如 QGIS 插件明确要求 GDAL ≥ 3.7),或者--libs输出里没有-lhdf5_hl -lhdf5(说明 HDF5 支持未启用),或者--includes路径指向/usr/include/gdal(这是系统包路径,通常不包含完整头文件),那就别犹豫了,编译是唯一解。

2. 编译前的“地基检查”:依赖库不是越多越好,而是要精准对齐

很多人一上来就git clone https://github.com/OSGeo/gdal.git && cd gdal && ./configure,结果卡在checking for proj_api.h... no或configure: error: libtiff not found上,然后开始疯狂apt install,装了一堆libproj-dev libtiff-dev libgeotiff-dev libnetcdf-dev,最后发现./configure还是报错。问题出在哪?你装的不是“依赖”,而是“依赖的依赖的依赖”——它们的版本、安装路径、ABI 兼容性,全都没对齐。编译 GDAL 不是搭乐高,不能随便混搭零件;它是一场精密手术,每个器官(依赖库)都必须来自同一具“供体”(版本生态)。

我给自己定了一条铁律:所有 GDAL 依赖库,必须全部从源码编译,且严格按官方推荐顺序安装。OSGeo 官方文档虽没明说,但 GDAL 的configure.ac脚本里,AC_CHECK_PROG和AC_CHECK_LIB的检测顺序就是隐含的依赖链。我们按这个逻辑,把最关键的五个依赖拆解清楚:

2.1 PROJ 库:坐标系转换的“心脏”,必须 ≥ 9.1.0

PROJ 是 GDAL 坐标变换能力的基石。低于 9.0 的 PROJ(如 Ubuntu 20.04 自带的 7.2.1)不支持+type=crs语法,会导致gdalwarp -t_srs EPSG:32650解析失败;而 9.3.0 之后引入的proj_create_crs_to_crs()API,是 GDAL 3.7+ 实现无损重投影的核心。所以,必须手动编译 PROJ。

# 下载 PROJ 9.3.1(2023年10月稳定版) wget https://download.osgeo.org/proj/proj-9.3.1.tar.gz tar -xzf proj-9.3.1.tar.gz && cd proj-9.3.1 # 关键:禁用 SQLite3 的 FTS5(避免与系统 SQLite 冲突),启用网络数据源 ./configure --prefix=/opt/proj-9.3.1 \ --without-sqlite3 \ --with-curl \ --enable-lto make -j$(nproc) && sudo make install sudo ldconfig # 刷新动态链接库缓存

注意:--without-sqlite3是经验之谈。很多系统 SQLite3 版本太老(< 3.35),不支持 FTS5,而 PROJ 的 configure 脚本一旦检测到 SQLite3 就会强制启用 FTS5,导致编译失败。我们宁可不用 FTS5,也要确保 PROJ 本身能编译成功。GDAL 后续会用自己的 SQLite3 链接选项。

2.2 GEOS 库:矢量计算的“大脑”,必须 ≥ 3.11.0

GEOS 提供Intersection,Union,Buffer等核心几何操作。GDAL 的ogr2ogr -dialect sqlite -sql "SELECT ST_Union(geometry) FROM layer"就依赖它。GEOS 3.10 以下版本在处理自相交多边形时有内存泄漏,曾导致我们一个国土调查项目批量处理时每小时崩一次。编译时务必开启--enable-python(为后续 GDAL Python 绑定铺路):

wget https://download.osgeo.org/geos/geos-3.12.0.tar.bz2 tar -xjf geos-3.12.0.tar.bz2 && cd geos-3.12.0 ./configure --prefix=/opt/geos-3.12.0 \ --enable-python \ --enable-lto make -j$(nproc) && sudo make install

2.3 HDF5 库:科学数据的“高速公路”,必须启用并行 I/O

遥感卫星数据(如 Landsat, Sentinel)大量使用 HDF5 格式。默认编译的 HDF5 是单线程的,读取一个 20GB 的 HDF5 文件可能要 8 分钟;而启用 MPI 并行 I/O 后,用 4 个进程可压缩到 2 分半。但 MPI 编译极复杂,对个人开发者不现实。折中方案是启用 POSIX 并行 I/O(--enable-parallel),它不依赖 MPI,仅需libpthread,却能提升 3 倍读取速度:

wget https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.14/hdf5-1.14.3/src/hdf5-1.14.3.tar.gz tar -xzf hdf5-1.14.3.tar.gz && cd hdf5-1.14.3 ./configure --prefix=/usr/local/hdf5 \ --enable-parallel \ --enable-build-mode=production \ --with-zlib=/usr \ --with-szlib=/usr make -j$(nproc) && sudo make install

2.4 NetCDF 库:气象海洋数据的“通用语言”,必须绑定 HDF5

NetCDF-C 4.x 本质是 HDF5 的一层封装。如果你先装 NetCDF 再装 HDF5,NetCDF 会链接到系统旧版 HDF5(如/usr/lib/x86_64-linux-gnu/libhdf5.so),导致 GDAL 后续链接时出现符号冲突。正确顺序是:先装好/usr/local/hdf5,再让 NetCDF 明确指向它:

wget https://github.com/Unidata/netcdf-c/archive/refs/tags/v4.9.2.tar.gz tar -xzf v4.9.2.tar.gz && cd netcdf-c-4.9.2 ./configure --prefix=/usr/local/netcdf \ --disable-dap \ --disable-netcdf-4 \ --with-hdf5=/usr/local/hdf5 \ --enable-static make -j$(nproc) && sudo make install

注意:--disable-netcdf-4是故意的。NetCDF-4 功能强大,但依赖太重(需 HDF5 + ZLIB + SZLIB),容易出错。我们只要 NetCDF-3 的经典接口,GDAL 完全够用,且更稳定。

2.5 SQLite3 与 SpatiaLite:属性查询的“搜索引擎”,必须启用 FTS5

GDAL 的 SQL 引擎(-dialect sqlite)重度依赖 SQLite3 的 FTS5 模块做全文检索。Ubuntu 22.04 自带的 SQLite3 是 3.37.2,已支持 FTS5,但默认编译时不启用。我们必须重新编译 SQLite3,确保fts5.c被包含:

wget https://www.sqlite.org/2023/sqlite-autoconf-3430000.tar.gz tar -xzf sqlite-autoconf-3430000.tar.gz && cd sqlite-autoconf-3430000 # 关键:定义 SQLITE_ENABLE_FTS5 CFLAGS="-DSQLITE_ENABLE_FTS5" ./configure --prefix=/usr/local/sqlite3 \ --enable-static \ --disable-readline make -j$(nproc) && sudo make install

完成这五步后,你的系统里就有了干净、可控、版本对齐的依赖“地基”。此时执行ls -l /opt/proj-9.3.1/lib/libproj.so*,确认软链接指向正确的主版本;执行pkg-config --modversion proj,输出9.3.1;执行sqlite3 --version,输出3.43.0 2023-08-24 12:34:56...并且echo "PRAGMA compile_options;" | sqlite3中能看到ENABLE_FTS5。这些,就是编译 GDAL 前必须点亮的“地基指示灯”。

3. GDAL 源码编译的“九道关卡”:configure 参数不是选项,而是契约

当所有依赖库就位,./configure就成了整场战役的总攻号角。网上流传的./configure --prefix=/usr/local是最大误区——它像一张空白支票,把控制权又交还给了自动探测脚本,而探测脚本往往“聪明反被聪明误”。真正的高手,会把./configure当成一份法律契约,每一项--with-*参数,都是对编译行为的精确承诺。我根据三年来在不同硬件(x86_64/ARM64)、不同系统(Ubuntu/CentOS/Rocky)、不同项目(遥感处理/三维建模/气象分析)的实战,提炼出必须显式声明的九个核心参数,缺一不可:

3.1 基础定位:--prefix与--with-pkgconfigdir的双重锚定

--prefix=/usr/local/gdal-3.8.0不只是指定安装路径,它更是告诉编译器:“所有头文件放/usr/local/gdal-3.8.0/include,所有库放/usr/local/gdal-3.8.0/lib,所有工具放/usr/local/gdal-3.8.0/bin”。但光有--prefix不够,因为pkg-config工具需要知道.pc文件在哪。很多教程漏掉--with-pkgconfigdir,导致pkg-config --cflags gdal返回空,CMake 项目找不到 GDAL。必须同步指定:

--prefix=/usr/local/gdal-3.8.0 \ --with-pkgconfigdir=/usr/local/gdal-3.8.0/lib/pkgconfig \

3.2 依赖库“点名录取”:--with-*参数的绝对路径锁定

这是最易错的环节。./configure会自动搜索/usr,/usr/local,/opt下的库,但自动搜索的结果不可控。我们必须用绝对路径“点名录取”,确保链接到我们亲手编译的版本:

--with-proj=/opt/proj-9.3.1 \ --with-geos=/opt/geos-3.12.0 \ --with-hdf5=/usr/local/hdf5 \ --with-netcdf=/usr/local/netcdf \ --with-sqlite3=/usr/local/sqlite3 \ --with-spatialite=yes \ # SpatiaLite 会自动找 SQLite3

注意:--with-spatialite=yes不写路径,是因为 SpatiaLite 的spatialite-config脚本会自动读取PKG_CONFIG_PATH,而我们稍后会设置它。强行写路径反而会破坏其自动探测逻辑。

3.3 功能开关:--with-*的布尔值陷阱

GDAL 有几十个--with-*开关,但很多新手不知道:--with-curl和--with-curl=yes效果完全不同!前者是“启用并自动探测”,后者是“启用并强制使用 yes 作为值”,而yes不是有效路径,会导致 configure 报错。正确写法永远是--with-curl(无等号)或--without-curl(禁用)。以下是生产环境必开的四个:

--with-curl \ # 启用 HTTP/HTTPS 数据源(WMS/WCS) --with-libjson \ # 启用 GeoJSON 读写(现代 Web GIS 标准) --with-openjpeg \ # 启用 JPEG2000(Sentinel-2 L1C 必需) --with-webp \ # 启用 WebP 压缩(轻量级地图瓦片)

3.4 Python 绑定:--with-python的 ABI 锁定术

--with-python默认使用python3命令,但很多系统python3指向的是/usr/bin/python3.10,而你用pyenv管理的项目 Python 是3.11。这会导致import osgeo.gdal时出现ImportError: libpython3.10.so.1.0: cannot open shared object file。解决方案是显式指定 Python 解释器路径和 ABI 标签:

--with-python=/home/user/.pyenv/versions/3.11.5/bin/python3.11 \ --with-python3-abi=3.11m \ # m 表示 pymalloc,Ubuntu/Debian 系统常用

3.5 性能优化:--enable-optimize与--enable-static的取舍

--enable-optimize会添加-O3 -march=native,让编译器针对当前 CPU 生成最优指令,实测在 Intel Xeon 上提升gdal_translate15% 速度。但它有个致命副作用:编译出的库无法移植到其他 CPU 架构(如从 Intel 移到 AMD EPYC)。所以,开发机用--enable-optimize,生产服务器用--enable-production(更保守的优化)。

--enable-static会把所有依赖(PROJ, GEOS, HDF5)静态链接进libgdal.so,生成一个“超级单体库”。好处是部署简单(拷贝一个文件就行),坏处是体积暴涨(从 20MB 到 120MB),且无法享受系统安全更新(如 OpenSSL 漏洞修复)。我的建议是:容器化部署用--enable-static,物理服务器用--enable-shared(默认)。

3.6 最终的 configure 命令:一份可复制的契约模板

综合以上,这是我在 Ubuntu 22.04 x86_64 上,为遥感处理项目生成的最终configure命令(已验证 100% 成功):

cd gdal-3.8.0 export PKG_CONFIG_PATH="/opt/proj-9.3.1/lib/pkgconfig:/opt/geos-3.12.0/lib/pkgconfig:/usr/local/hdf5/lib/pkgconfig:/usr/local/netcdf/lib/pkgconfig:/usr/local/sqlite3/lib/pkgconfig" ./configure --prefix=/usr/local/gdal-3.8.0 \ --with-pkgconfigdir=/usr/local/gdal-3.8.0/lib/pkgconfig \ --with-proj=/opt/proj-9.3.1 \ --with-geos=/opt/geos-3.12.0 \ --with-hdf5=/usr/local/hdf5 \ --with-netcdf=/usr/local/netcdf \ --with-sqlite3=/usr/local/sqlite3 \ --with-spatialite=yes \ --with-curl \ --with-libjson \ --with-openjpeg \ --with-webp \ --with-python=/usr/bin/python3.10 \ --with-python3-abi=3.10 \ --enable-optimize \ --enable-shared \ --with-libtiff=internal \ --with-jpeg=internal \ --with-png=internal

注意:--with-libtiff=internal等内部编译选项,是为了规避系统libtiff版本混乱的问题。GDAL 自带的third_party/libtiff是经过充分测试的稳定版本,比系统源里的更可靠。

执行此命令后,configure输出的最后一行应是GDAL is now configured for ...,且下方列出的所有Enabled:项都为yes。如果看到Disabled:后面跟着你想要的功能(如openjpeg),说明路径或依赖有问题,必须回溯检查。

4. 编译、安装与验证:从 make 到 “Hello GDAL”的全流程实操

./configure成功只是万里长征第一步。接下来的make、make install、环境配置、Python 绑定,每一步都有隐藏的“雷区”。我记录过一次完整的编译日志,从make开始到import osgeo.gdal成功,共耗时 47 分钟(在 32 核 AMD EPYC 服务器上),其中 38 分钟花在了make,5 分钟在make install,剩下 4 分钟全在解决环境变量和 Python 路径问题。下面,我把这 47 分钟拆解成可复现的步骤,并标注每个环节的“心跳监测点”。

4.1 make:并行编译的节奏控制与内存监控

make -j$(nproc)是标准写法,但并非总是最优。GDAL 的 C++ 源码(尤其是frmts/grib/和frmts/hdf5/)在高并发下会触发 GCC 的内存溢出(OOM Killer),导致make中途被 kill。我的经验是:物理内存 < 32GB 时,用-j$(nproc);≥ 32GB 时,用-j$(nproc) -l$(nproc)(限制负载)。

# 监控内存使用,新开终端执行 watch -n 1 'free -h | grep Mem' # 开始编译(假设 64GB 内存) make -j32 -l32 2>&1 | tee build.log

tee build.log很关键。当make卡住时,不要 Ctrl+C,而是tail -n 50 build.log查看最后 50 行。常见卡点有:

  • Compiling ogr/ogrsf_frmts/gml2/gml2handler.cpp:这是 GML 解析器,编译慢但正常;
  • Linking ogr/ogrsf_frmts/gml2/ogrgml2driver.so:链接阶段,如果卡超过 5 分钟,可能是ld内存不足,需加-Wl,--no-as-needed(稍后在LDFLAGS里加)。

如果make失败,绝不要make clean && make重来。GDAL 的构建系统有缓存,make clean会清空所有中间文件,下次make又要从头编译。正确做法是:make -k(继续编译,忽略错误),然后定位到报错的.o文件所在目录,单独make xxx.o,再make。

4.2 make install:权限、符号链接与 pkg-config 的三重校验

sudo make install看似简单,但有三个必须人工校验的点:

  1. 权限校验:ls -l /usr/local/gdal-3.8.0/lib/libgdal.so*应显示root:root且权限为755。如果看到644,说明install命令没加sudo,库文件不可执行,后续ldd会报错。

  2. 符号链接校验:ls -l /usr/local/gdal-3.8.0/lib/libgdal.so*应有libgdal.so -> libgdal.so.30和libgdal.so.30 -> libgdal.so.30.1.8。如果只有libgdal.so.30.1.8,说明make install没生成链接,需手动:

    cd /usr/local/gdal-3.8.0/lib sudo ln -sf libgdal.so.30.1.8 libgdal.so.30 sudo ln -sf libgdal.so.30 libgdal.so
  3. pkg-config 校验:pkg-config --modversion gdal必须输出3.8.0,pkg-config --cflags gdal必须输出-I/usr/local/gdal-3.8.0/include。如果失败,检查PKG_CONFIG_PATH是否包含/usr/local/gdal-3.8.0/lib/pkgconfig,并执行sudo ldconfig刷新系统库缓存。

4.3 环境变量:LD_LIBRARY_PATH 与 PYTHONPATH 的“双保险”

即使make install成功,终端里直接运行gdalinfo --version仍可能报command not found。这是因为/usr/local/gdal-3.8.0/bin不在PATH里。同理,import osgeo.gdal会失败,因为 Python 找不到libgdal.so。必须设置两个环境变量:

# 永久生效(写入 ~/.bashrc) echo 'export PATH="/usr/local/gdal-3.8.0/bin:$PATH"' >> ~/.bashrc echo 'export LD_LIBRARY_PATH="/usr/local/gdal-3.8.0/lib:$LD_LIBRARY_PATH"' >> ~/.bashrc echo 'export PYTHONPATH="/usr/local/gdal-3.8.0/lib/python3.10/site-packages:$PYTHONPATH"' >> ~/.bashrc source ~/.bashrc # 立即生效(当前终端) export PATH="/usr/local/gdal-3.8.0/bin:$PATH" export LD_LIBRARY_PATH="/usr/local/gdal-3.8.0/lib:$LD_LIBRARY_PATH" export PYTHONPATH="/usr/local/gdal-3.8.0/lib/python3.10/site-packages:$PYTHONPATH"

注意:PYTHONPATH的路径必须与--with-python指定的 Python 版本完全一致。/usr/bin/python3.10对应python3.10/site-packages,/usr/bin/python3.11对应python3.11/site-packages。写错一个字符,import就失败。

4.4 终极验证:“Hello GDAL”的七层测试

不要满足于gdalinfo --version。真正的验证是七层递进的“Hello World”:

  1. 命令行工具层:gdalinfo --version→ 输出GDAL 3.8.0, released 2023/10/19
  2. C API 层:写一个test_c.c,调用GDALAllRegister(),编译gcc test_c.c -lgdal -o test_c && ./test_c,无段错误即通过。
  3. Python 层:python3 -c "from osgeo import gdal; print(gdal.__version__)"→ 输出3.8.0
  4. 驱动支持层:python3 -c "from osgeo import gdal; print([gdal.GetDriver(i).ShortName for i in range(gdal.GetDriverCount()) if 'GTiff' in gdal.GetDriver(i).ShortName])"→ 输出['GTiff']
  5. 编译选项层:gdal-config --libs→ 输出应包含-L/usr/local/gdal-3.8.0/lib -lgdal -lproj -lgeos_c -lhdf5_hl -lhdf5
  6. 功能启用层:gdalinfo --formats | grep -i "hdf5\|netcdf\|openjpeg"→ 应看到HDF5 -raster- (rw+vs): Hierarchical Data Format Release 5等
  7. 业务逻辑层:gdal_translate -of GTiff -co COMPRESS=LZW -co TILED=YES input.tif output.tif→ 生成的output.tif用gdalinfo output.tif检查COMPRESSION=LZW和TILED=YES是否生效

第七层是“业务逻辑层”,它把技术验证拉回到真实场景。只有当output.tif真正被压缩、分块,且大小比原文件小 40%,才算真正成功。这七层,是我每次编译后必跑的回归测试,少一层,心里都不踏实。

5. 常见故障排查:从 “undefined symbol” 到 “No module named osgeo” 的全链路诊断

编译安装完成后,90% 的问题不出现在make阶段,而出现在运行时。这些错误信息往往晦涩难懂,比如ImportError: /usr/local/gdal-3.8.0/lib/libgdal.so.30: undefined symbol: proj_coordoperation_get_method_id,表面看是 PROJ 符号缺失,实则根源在libproj.so的版本冲突。下面,我按故障现象分类,给出从现象到根因的完整诊断链路,每一步都附带shell命令和预期输出。

5.1 “command not found”:PATH 与 bin 目录的迷宫

现象:gdalinfo --version报command not found
诊断链路:

  1. which gdalinfo→ 如果无输出,说明PATH未包含/usr/local/gdal-3.8.0/bin
  2. ls -l /usr/local/gdal-3.8.0/bin/gdalinfo→ 如果报No such file or directory,说明make install未成功,或--prefix路径写错
  3. echo $PATH | tr ':' '\n' | grep gdal→ 确认/usr/local/gdal-3.8.0/bin在PATH中

修复:export PATH="/usr/local/gdal-3.8.0/bin:$PATH",并写入~/.bashrc

5.2 “undefined symbol”:动态链接库的版本战争

现象:gdalinfo --version报undefined symbol: proj_coordoperation_get_method_id
诊断链路:

  1. ldd $(which gdalinfo) | grep proj→ 输出类似libproj.so.25 => /usr/lib/x86_64-linux-gnu/libproj.so.25 (0x00007f...),说明链接到了系统libproj.so.25,而非我们编译的/opt/proj-9.3.1/lib/libproj.so.29
  2. readelf -d $(which gdalinfo) | grep NEEDED | grep proj→ 确认二进制期望的libproj.so名称
  3. ls -l /opt/proj-9.3.1/lib/libproj.so*→ 确认我们编译的库存在,且libproj.so.29是主链接

根因:LD_LIBRARY_PATH未设置,或设置在sudo环境下失效(sudo默认不继承LD_LIBRARY_PATH)
修复:export LD_LIBRARY_PATH="/opt/proj-9.3.1/lib:/usr/local/gdal-3.8.0/lib:$LD_LIBRARY_PATH",并验证ldd $(which gdalinfo) | grep proj指向/opt/proj-9.3.1/lib/libproj.so.29

5.3 “No module named osgeo”:Python 绑定的路径幻觉

现象:python3 -c "import osgeo.gdal"报ModuleNotFoundError: No module named 'osgeo'
诊断链路:

  1. python3 -c "import sys; print('\n'.join(sys.path))"→ 检查输出中是否有/usr/local/gdal-3.8.0/lib/python3.10/site-packages
  2. ls -l /usr/local/gdal-3.8.0/lib/python3.10/site-packages/osgeo/→ 确认__init__.py和_gdal.cpython-*.so存在
  3. python3 -c "import osgeo.gdal; print(osgeo.gdal.__file__)"→ 如果上一步成功,此命令应输出.so文件路径

根因:PYTHONPATH未设置,或设置的 Python 版本与--with-python不匹配
修复:export PYTHONPATH="/usr/local/gdal-3.8.0/lib/python3.10/site-packages:$PYTHONPATH",并确认python3 --version是3.10.x

5.4 “driver not found”:驱动注册的静默失败

现象:gdalinfo input.hdf报input.hdf: not recognized as a supported file format
诊断链路:

  1. gdalinfo --formats | grep -i hdf→ 如果无输出,说明 HDF5 驱动未注册
  2. gdal-config --libs | grep hdf5→ 如果无-lhdf5_hl -lhdf5,说明--with-hdf5未生效
  3. cat /usr/local/gdal-3.8.0/lib/pkgconfig/gdal.pc | grep Libs→ 检查Libs.private是否包含-lhdf5_hl -lhdf5

根因:./configure时--with-hdf5路径错误,或hdf5库未正确安装(/usr/local/hdf5/lib/libhdf5.so不存在)
修复:重新运行./configure,确保--with-hdf5=/usr/local/hdf5,并验证ls /usr/local/hdf5/lib/libhdf5*

5.5 “segmentation fault”:ABI 不兼容的终极杀手

现象:gdal_translate input.tif output.tif运行几秒后 Segmentation fault
诊断链路:

  1. gdb --args gdal_translate input.tif output.tif→ 启动调试器
  2. (gdb) run→ 触发崩溃
  3. (gdb) bt→ 查看栈回溯,定位
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进