第03章 - 安装配置与环境搭建

3.1 装之前先回答三个问题

PDAL 的安装失败,绝大多数不是命令敲错,而是装法选错。动手前先确定三件事:

  1. 只要命令行,还是要 C++/Python 开发能力? 只要命令行,conda 或 Docker 一条命令就能用;要写 C++ 扩展,必须装开发文件(头文件 + 库);只要 Python,pip install pdal 仍然需要底层有可用的 PDAL 库。
  2. 能不能连外网? 内网离线环境要用 conda 的离线包或自建镜像,源码编译要提前把依赖全备齐。
  3. 版本要不要固定? 生产环境必须固定。PDAL 的 minor 版本会改默认行为(见第 1 章 writers.las.minor_version 的例子),跟着 latest 走迟早踩到。

本章以 PDAL 2.10.0 为基线,覆盖四个平台方向:conda(全平台首选)、Docker(服务化/批处理)、pip(Python)、源码编译(定制与内网)。

3.2 依赖清单:以源码为准,不要以文档为准

PDAL 的编译期依赖写在 cmake/*.cmake 里,比文档新也硬。2.10.0 的关键约束:

表 3-1 PDAL 2.10.0 的必需依赖(取自源码 cmake 脚本)

依赖 版本要求 出处 用途
CMake ≥ 3.13 CMakeLists.txt 的 cmake_minimum_required 构建系统
GDAL ≥ 3.8 cmake/gdal.cmake 里显式 FATAL_ERROR 检查 坐标系、栅格/矢量驱动
PROJ ≥ 9.0 cmake/proj.cmake:find_package(PROJ 9.0 REQUIRED CONFIG) 坐标转换
GeoTIFF ≥ 1.7.0 cmake/geotiff.cmake LAS 里 GeoKey 支持
curl 必需 cmake/curl.cmake:find_package(CURL REQUIRED) 远程文件(EPT/COPC/HTTP)
zlib / liblzma 必需 cmake/zlib.cmake、cmake/lzma.cmake 压缩
laz-perf 随源码内嵌 vendor/lazperf LAZ 编解码

这里有两处文档与源码不一致,必须按源码来:

  • 官方 doc/development/compilation/unix.md 写 “PDAL requires at least version 3.5 of CMake”,但顶层 CMakeLists.txt 实际是 cmake_minimum_required(VERSION 3.13);
  • doc/development/compilation/dependencies.md 写 GeoTIFF “1.3+”,cmake/geotiff.cmake 实际要求 1.7.0。

照文档装低版本依赖,会在 CMake 配置阶段直接失败。这条经验对任何 C++ 项目都成立:版本下限看构建脚本,行为说明看文档。

还有一条历史坑值得写进团队 wiki:GDAL 内部会嵌入一份 libgeotiff 并剥掉 PDAL 需要的符号,所以 PDAL 不能简单链接系统 GDAL。如果你自己编译这两个库,构建 GDAL 时必须打开 “External libgeotiff”;用 conda-forge 的话这个问题已经处理好,不用管。

3.3 首选方案:conda-forge

Windows 上这是官方唯一推荐的二进制渠道(只提供 64 位),Linux/macOS 同样可用。

# 新建独立环境并装上 PDAL 命令行
conda create --yes --name pdal --channel conda-forge pdal
conda activate pdal

# 需要 Python 绑定时(会连带装上 gdal)
conda install -c conda-forge python-pdal gdal

包名要分清,官方文档写得很明确:

包名 装什么 适用
pdal 命令行程序 和 开发文件 C++ 开发、命令行使用
libpdal 只有基础库 自己写程序链接 PDAL
python-pdal Python 扩展(依赖 pdal) Python 调用

不要把 PDAL 装进 base 环境。 官方在 quickstart 里专门用 warning 强调过这一点。base 环境里既有 Python 又有各种地理库时,conda 的 solver 很容易为了满足版本约束把 GDAL/PROJ 降级,进而破坏其他工具链。

升级与查看:

conda update pdal
conda list pdal

conda list 显示的是包版本,不一定等于 pdal --version——如果 PATH 里有另一个 PDAL(比如之前手动编译在 /usr/local/bin 的),命令行的实际行为可能来自那个。用 which pdal(Windows 用 where pdal)确认可执行文件路径。

3.4 Docker:批处理与服务化

仓库和 Docker Hub 维护两个镜像标签(doc/project/docker.md):

  • pdal/pdal:latest:跟随 master
  • pdal/pdal:<version>:跟随当前发布版
# 交互式跑一条 pipeline
docker run --rm -v "$PWD":/data -w /data pdal/pdal:2.10.0 \
    pdal pipeline tin.json

# 直接在容器里执行任意 pdal 子命令
docker run --rm -v "$PWD":/data -w /data pdal/pdal:2.10.0 \
    pdal info --summary /data/input.las

要点三个:

  • -w /data 必须设,否则相对路径解析在以镜像 WORKDIR 为基准的位置,pipeline 里的相对文件名会找不到;
  • 用版本号标签,别用 latest。latest 跟 master,行为随时会变;
  • 容器默认不带数据,务必用 -v 挂载,别用 docker cp 来回搬几十 GB 的点云。

镜像里附带的环境是可复现的(依赖由镜像构建时锁定),这也是批处理平台最省事的部署形态:把 pipeline JSON 和输入挂进去,输出挂出来,剩下交给调度器。

3.5 Python 绑定:pip 与 conda 两条路

doc/python.md 说得很清楚:PDAL 的 Python 支持分两层,一层是把 Python 嵌进 pipeline(filters.python),一层是让 Python 调 PDAL(pdal 扩展)。两者都与 NumPy 强绑定——数据以 NumPy 数组进出。

conda 路线(最省心,会连带安装 PDAL):

conda create -n pdalpy -c conda-forge python-pdal
conda activate pdalpy
python -c "import pdal; print(pdal.__version__)"

pip 路线(要求系统里已有可用的 PDAL 库):

pip install PDAL

如果 import pdal 报 ImportError: libpdalcpp.so…: cannot open shared object file,说明 Python 扩展编好了但运行时找不到 PDAL 库——这是 pip 路线最典型的问题,解决方式是让动态链接器能找到库:

# Linux:把 PDAL 库目录加入搜索路径(或写进 /etc/ld.so.conf)
export LD_LIBRARY_PATH=/usr/local/lib:\$LD_LIBRARY_PATH

# macOS
export DYLD_LIBRARY_PATH=/usr/local/lib:\$DYLD_LIBRARY_PATH

Windows 上通常表现为 DLL load failed,把 pdalcpp.dll 所在目录加入 PATH 即可。这也解释了为什么 Windows 上更推荐 conda——它把 DLL 搜索路径一并配好了。

2.1 版本之后有一个变化要记住:以前 Python 相关能力分散在嵌入的 readers.numpy/filters.python 与 PyPI 扩展两处;从 PDAL 2.1 / pdal-python 2.3 起,嵌入 stage 与扩展都从 PyPI 分发。

3.6 源码编译:Unix 与 Windows

需要定制(打开特定插件、内网离线、打补丁)时才走这条路。官方 Unix 流程是 CMake + Ninja:

git clone https://github.com/PDAL/PDAL.git
cd PDAL
git checkout 2.10.0          # 生产环境钉 tag,不要跟 master

mkdir build && cd build
cmake -G Ninja ..
ninja
sudo ninja install

Unix 上依赖通常只需要先装 GDAL,其余由包管理自动带出:

# Debian / Ubuntu
sudo apt install libgdal-dev libgeotiff-dev libproj-dev libxml2-dev

# 或走 conda 依赖
conda install gdal geotiff proj curl zlib xz

Windows 上官方推荐用 conda 提供全部依赖,再调 MSVC 编译。GitHub Actions 的 scripts/ci/win 目录就是权威的依赖清单,其 conda install 一行大致是:

conda install geotiff laszip nitro curl ^
   gdal pcl cmake eigen ninja libgdal ^
   zstd numpy xz libxml2 laz-perf qhull ^
   sqlite hdf5 tiledb conda-build ninja -y

然后:

cmake -G "NMake Makefiles" ..
nmake /f Makefile

几个 CMake 开关值得记(来自 cmake/options.cmake)。注意它们的默认值普遍是 OFF,意味着“不显式打开就没有”:

选项 默认 说明
WITH_TESTS ON 是否构建单元测试
WITH_GCS ON 谷歌云存储支持(需要 OpenSSL)
WITH_COMPLETION OFF bash 补全脚本
BUILD_PLUGIN_PGPOINTCLOUD OFF PostgreSQL PointCloud 读写
BUILD_PLUGIN_E57 OFF E57 读写
BUILD_PLUGIN_TILEDB OFF TileDB 读写
BUILD_PLUGIN_HDF OFF HDF5 读取
BUILD_PLUGIN_MATLAB OFF .mat 读写
BUILD_PLUGIN_ARROW OFF Arrow/Parquet 读写
BUILD_PLUGIN_TRAJECTORY OFF 由 LAS 推算轨迹(需 Ceres)

所以“文档里有 readers.e57,为什么我的 pdal --drivers 里没有”这个问题,答案往往就在这里——编译时没开 BUILD_PLUGIN_E57。

打开方式:

cmake -G Ninja \
  -DBUILD_PLUGIN_E57=ON \
  -DBUILD_PLUGIN_PGPOINTCLOUD=ON \
  -DCMAKE_BUILD_TYPE=Release \
  ..

编译完成后的快速验证:

ls bin/pdal
bin/pdal --version
bin/pdal --drivers | head
ctest                       # 只想确认功能可用时跑一遍

3.7 装完必做的五项检查

装完不要急着建 pipeline,先按顺序验五件事。任何一项失败,后面都会以更难懂的形式炸出来。

# 1. 版本与构建信息
pdal --version
# pdal 2.10.0 (git-version: Release)

# 2. 可用 stage 数量与关键 stage 是否存在
pdal --drivers | wc -l
pdal --drivers | grep -E "readers.las|filters.smrf|writers.gdal"

# 3. 可用子命令
pdal --list-commands

# 4. 某个 stage 的完整选项表(比查文档快,且与当前二进制一致)
pdal --options writers.gdal
pdal --options all | head -100

# 5. 端到端冒烟测试
pdal info --summary your.las

第 4 条特别值得养成习惯:pdal --options <stage> 打印的是当前这个二进制的参数、类型与默认值。文档写的是某个版本的行为,而你的二进制可能是另一版。遇到“参数不生效”时,先用它核对参数名。

pdal --drivers 有个隐藏参数 --showjson,输出 JSON 而不是表格,每个 stage 带 name、description、link、extensions、streamable 五个字段。streamable 正好回答第 1 章留下的问题:这条 stage 能不能走流式。

pdal --drivers --showjson | python -c "
import json,sys
for d in json.load(sys.stdin):
    print(d['name'], d['streamable'])
"

3.8 环境变量与路径

变量 作用 备注
PDAL_DRIVER_PATH 追加插件搜索目录 Linux/macOS 用 :,Windows 用 ; 分隔
LD_LIBRARY_PATH / DYLD_LIBRARY_PATH / PATH 运行时库搜索 pip 安装的 Python 扩展依赖此路径找 libpdalcpp
PROJ_DATA(旧版 PROJ_LIB) PROJ 的坐标数据库目录 坐标系解析失败时优先查它
GDAL_DATA GDAL 数据文件目录 某些驱动与坐标系统依赖
GDAL_CACHEMAX GDAL 栅格缓存(MB) readers.gdal 对缓存设置很敏感

最后一条来自 readers.gdal 的官方提示:这个 reader 严重依赖 GDAL 的缓存设置,读大栅格时调 GDAL_CACHEMAX 往往比换机器有效。

3.9 常见故障对照

现象 原因 处理
cmake 报 Required at least GDAL version 3.8 系统 GDAL 太老 用 conda 装 GDAL,或从源码编译
Could NOT find PROJ (missing: PROJ_DIR) PROJ 9 未安装或未走 CONFIG 模式 conda install proj,或设 -DPROJ_DIR=
CMake 阶段报 GeoTIFF 版本不足 文档说 1.3,源码要 1.7.0 升 GeoTIFF;或让 GDAL 带 external libgeotiff
pdal: command not found 环境未激活 / 安装前缀不在 PATH conda activate 或把 bin 加进 PATH
pdal --drivers 缺某个 stage 编译时插件开关为 OFF 重新 cmake 打开 BUILD_PLUGIN_*
ImportError: libpdalcpp.so 运行时找不到 PDAL 库 设 LD_LIBRARY_PATH,或改用 conda 安装
DLL load failed(Windows) pdalcpp.dll 不在 PATH 把 PDAL bin 加入 PATH,或用 conda
插件加载了但 pipeline 报 Couldn't create stage 插件版本与主库 ABI 不匹配 用同一工具链、同一版本重新编译插件
坐标转换报 proj_create: no database context specified PROJ_DATA 未设置或指向错误目录 指向 <prefix>/share/proj

最后一条在 Python 环境里出现得不少。conda 装的 PROJ 数据在 $CONDA_PREFIX/share/proj,如果从别的 shell 或系统服务里调用 Python,这个前缀可能没生效。PDAL 官方文档里的 Python 示例就直接预置了这一步:

import os, sys
conda_env_path = os.environ.get('CONDA_PREFIX', sys.prefix)
proj_data = os.path.join(conda_env_path, 'share', 'proj')
os.environ["PROJ_DATA"] = proj_data

3.10 生产建议

镜像/环境锁到 patch 版本。 pdal/pdal:2.10.0、conda install pdal=2.10.0,而不是 latest。记录 pdal --version 的完整输出(含 git sha)到部署清单。

优先 Docker 或 conda 环境,避免系统级散装安装。 PDAL 依赖 GDAL/PROJ/GeoTIFF 三个版本敏感的库,系统包管理器一升级就可能把整条链带崩。容器或独立 conda 环境是唯一能保证“半年后还能跑出同样结果”的方案。

把 pdal --options <stage> 的输出纳入测试基线。 升级 PDAL 后 diff 一下关键 stage 的选项表,比读 release note 更可靠地发现默认值变化。

内网环境提前备好依赖。 源码编译需要 GDAL/PROJ/GeoTIFF/curl/zlib/lzma 全套开发包;离线 conda 需要 conda pack 打包整个环境。别在目标机器上第一次尝试编译。

别在同一台机器上混装多套 PDAL。 系统包、conda、源码、Docker 各来一份时,pdal 指向哪一个取决于 PATH 顺序,插件搜索路径也可能串。用容器隔离,或者至少用绝对路径调用。

3.11 小结

主题 关键事实
版本基线 PDAL 2.10.0;CMake ≥ 3.13、GDAL ≥ 3.8、PROJ ≥ 9.0、GeoTIFF ≥ 1.7.0
首选安装 conda create -n pdal -c conda-forge pdal(Windows 官方推荐 64 位 conda)
包区分 pdal(命令行+开发文件)/ libpdal(库)/ python-pdal(Python 扩展)
Docker pdal/pdal:latest 跟 master,pdal/pdal:<ver> 跟发布;必须 -v 挂载与 -w 指定工作目录
Python conda 最省心;pip 需要系统 PDAL,且要配 LD_LIBRARY_PATH
插件 BUILD_PLUGIN_* 默认 OFF,没开就没有对应 stage
验证 --version、--drivers、--list-commands、--options <stage>、info --summary
路径变量 PDAL_DRIVER_PATH、LD_LIBRARY_PATH、PROJ_DATA、GDAL_CACHEMAX