使用 Arrow 调试代码#

Arrow C++ 的 GDB 扩展#

默认情况下,当要求打印 C++ 对象的值时,GDB 会显示其成员变量的内容。但是,对于 C++ 对象来说,这通常不会产生非常有用的输出,因为 C++ 类倾向于将其实现细节隐藏在方法和访问器后面。

例如,以下是 GDB 可能显示 arrow::Status 实例的方式

$3 = {
  <arrow::util::EqualityComparable<arrow::Status>> = {<No data fields>},
  <arrow::util::ToStringOstreamable<arrow::Status>> = {<No data fields>},
  members of arrow::Status:
  state_ = 0x0
}

以及 arrow::Decimal128Scalar

$4 = (arrow::Decimal128Scalar) {
  <arrow::DecimalScalar<arrow::Decimal128Type, arrow::Decimal128>> = {
    <arrow::internal::PrimitiveScalarBase> = {
      <arrow::Scalar> = {
        <arrow::util::EqualityComparable<arrow::Scalar>> = {<No data fields>},
        members of arrow::Scalar:
        _vptr.Scalar = 0x7ffff6870e78 <vtable for arrow::Decimal128Scalar+16>,
        type = std::shared_ptr<arrow::DataType> (use count 1, weak count 0) = {
          get() = 0x555555ce58a0
        },
        is_valid = true
      }, <No data fields>},
    members of arrow::DecimalScalar<arrow::Decimal128Type, arrow::Decimal128>:
    value = {
      <arrow::BasicDecimal128> = {
        <arrow::GenericBasicDecimal<arrow::BasicDecimal128, 128, 2>> = {
          static kHighWordIndex = <optimized out>,
          static kBitWidth = 128,
          static kByteWidth = 16,
          static LittleEndianArray = <optimized out>,
          array_ = {
            _M_elems = {[0] = 1234567, [1] = 0}
          }
        },
        members of arrow::BasicDecimal128:
        static kMaxPrecision = 38,
        static kMaxScale = 38
      }, <No data fields>}
  }, <No data fields>}

幸运的是,GDB 还允许自定义扩展覆盖特定类型的默认打印。我们提供了一个用 Python 编写的 GDB 扩展,它可以为常见的 Arrow C++ 类启用漂亮的打印,从而实现更高效的调试体验。例如,以下是前面提到的 arrow::Status 实例的显示方式

$5 = arrow::Status::OK()

以及与上面相同的 arrow::Decimal128Scalar 实例

$6 = arrow::Decimal128Scalar of value 123.4567 [precision=10, scale=4]

手动加载#

要启用 Arrow 的 GDB 扩展,您只需将其 下载 到您计算机上的某个位置,然后从 GDB 提示符下 source

(gdb) source path/to/gdb_arrow.py

您必须在每个新的 GDB 会话中对其进行 source 操作。您可能希望通过在 gdbinit 文件中添加 source 调用使其成为隐式操作。

自动加载#

GDB 提供了一种工具,可以为调试会话中涉及的每个目标文件或库自动加载脚本或扩展。您需要

  1. 找出 GDB 安装的*自动加载*位置。这可以使用 GDB 提示符上的 show 子命令来确定;答案将取决于操作系统。

    以下是 Ubuntu 上的示例

    (gdb) show auto-load scripts-directory
    List of directories from which to load auto-loaded scripts is $debugdir:$datadir/auto-load.
    (gdb) show data-directory
    GDB's data directory is "/usr/share/gdb".
    (gdb) show debug-file-directory
    The directory where separate debug symbols are searched for is "/usr/lib/debug".
    

    这告诉您用于自动加载的目录是 $debugdir$datadir/auto-load,它们分别扩展为 /usr/lib/debug//usr/share/gdb/auto-load

  2. 找出 Arrow C++ DLL 的完整路径,*所有符号链接都已解析*。例如,您可能已将 Arrow 7.0 安装在 /usr/local 中,则 Arrow C++ DLL 的路径可能是 /usr/local/lib/libarrow.so.700.0.0

  3. 确定实际的自动加载脚本路径。它的计算方法是:*a)* 获取您选择的自动加载目录的路径,*b)* 追加 Arrow C++ DLL 的完整路径,*c)* 在尾部追加 -gdb.py

    在上面的示例中,如果我们选择 /usr/share/gdb/auto-load 作为自动加载目录,则自动加载脚本的完整路径必须是 /usr/share/gdb/auto-load/usr/local/lib/libarrow.so.700.0.0-gdb.py

  4. GDB 扩展 复制或符号链接到步骤 3 中确定的文件路径。

如果一切顺利,那么 sobald GDB 遇到 Arrow C++ DLL 时,它将自动加载 Arrow GDB 扩展,以便在显示提示符上漂亮地打印 Arrow C++ 类。

支持的类#

Arrow GDB 扩展为核心的 Arrow C++ 类提供漂亮的打印

重要的实用程序类也包括在内