开发指南#

本节提供希望为 C++ 代码库做出贡献的开发人员的信息。

注意

由于大多数项目的开发人员都在 Linux 或 macOS 上工作,因此并非所有功能或开发工具都可以在 Windows 上得到一致的支持。如果您在 Windows 上,请查看 在 Windows 上开发

编译器警告级别#

BUILD_WARNING_LEVEL CMake 选项在我们将用于代码整洁的预定义编译器警告级别之间切换。对于发布版本,默认警告级别为 PRODUCTION,而对于调试版本,默认警告级别为 CHECKIN

在调试版本中使用 CHECKIN 时,使用 gcc 和 clang 时会添加 -Werror,导致任何警告都导致构建失败,并且 /WX 设置为 MSVC 具有相同的效果。

运行单元测试#

-DARROW_BUILD_TESTS=ON CMake 选项启用单元测试可执行文件的构建。然后,您可以通过启动所需的执行文件来单独运行它们,或者通过启动 ctest 可执行文件(它是 CMake 套件的一部分)来一次运行所有测试。

可能的调用类似于

$ ctest -j16 --output-on-failure

其中 -j16 选项并行运行最多 16 个测试,利用了多个 CPU 内核和硬件线程。

运行基准测试#

-DARROW_BUILD_BENCHMARKS=ON CMake 选项启用基准测试可执行文件的构建。然后,您可以通过从命令行启动相应的可执行文件来单独运行基准测试,例如

$ ./build/release/arrow-builder-benchmark

注意

为了获得有意义的基准测试数字,强烈建议在 Release 模式下构建,以便启用编译器优化。

代码风格、代码风格检查和 CI#

此项目遵循 Google 的 C++ 样式指南,但有以下例外

  • 我们将行长限制放宽到 90 个字符。

  • 我们在头文件中使用 NULLPTR 宏(而不是 nullptr),该宏在 src/arrow/util/macros.h 中定义,以支持构建 C++/CLI (ARROW-1134)。

  • 我们放宽了指南关于结构的规则。对于公共头文件,我们应该只在对象是主要简单的數據容器时使用结构,在这些容器中,公开所有内部成员是可以的,并且任何方法都主要是便利性。对于私有头文件,规则进一步放宽,并且结构可以在方便的情况下使用,用于不需要访问控制的类型,即使它们可能不是简单的數據容器。

  • 我们更喜欢指针用于输出和输入/输出参数(样式指南在某些情况下推荐可变引用)。

我们在 GitHub Actions 上的持续集成构建在各种平台和配置上运行单元测试套件,包括使用 Address Sanitizer 和 Undefined Behavior Sanitizer 来检查各种类型的错误行为模式,例如内存泄漏。此外,代码库还接受了许多代码风格和代码清洁度检查。

为了能够通过 CI 构建,您修改的 Git 分支必须通过以下检查

  • 使用项目的活动版本的 clang 进行 C++ 构建,并且在 -DBUILD_WARNING_LEVEL=CHECKIN 的情况下不出现编译器警告。请注意,存在一些类别的警告(例如 -Wdocumentation,下面将详细介绍),这些警告不会被 gcc 捕获。

  • 通过各种 C++(和其他)样式检查,使用 Archerylint 子命令进行检查。这也可以通过在本地运行 archery lint --cpplint --clang-format --clang-tidy --fix 来修复。

  • CMake 文件通过样式检查,可以通过运行 archery lint --cmake-format --fix 来修复。这需要 Python 3 和 cmake_format(注意:目前这在 Windows 上不起作用)。

在拉取请求上,“Dev / Lint”管道将运行这些检查,并报告哪些文件/行需要修复(如果有)。

为了解决 clang-format 在 LLVM 主要版本之间行为的差异,我们固定了使用的 clang-format 版本。您可以通过在 .env 中找到 CLANG_TOOLS 变量值来确认当前固定的版本。请注意,版本必须完全匹配;更新的版本(即使是补丁版本)也不起作用。LLVM 可以通过系统包管理器或 Conda 或 Homebrew 之类的包管理器安装,但请注意它们可能不提供所需的精确版本。或者,可以从 LLVM 网站 直接下载二进制文件。

为了方便起见,除了 Archery 之外,还可以通过构建来运行 C++ 样式检查。为此,构建一个或多个目标 format(用于 clang-format)、lint_cpp_clilint(用于 cpplint)或 clang-tidy。例如

$ cmake -GNinja ../cpp ...
$ ninja format lint clang-tidy lint_cpp_cli

根据您安装 clang-format 的方式,构建系统可能无法找到它。在这种情况下,调用 CMake 将显示以下错误

-- clang-format 12 not found

或者如果安装了错误的版本

-- clang-format found, but version did not match "^clang-format version 12"

您可以使用环境变量 $CLANG_TOOLS_PATH 提供包含 clang-format 可执行文件和其他文件的目录的显式路径,或者在调用 CMake 时传递 -DClangTools_PATH=$PATH_TO_CLANG_TOOLS。例如

# We unpacked LLVM here:
$ ~/tools/bin/clang-format --version
clang-format version 12.0.0
# Pass the directory containing the tools to CMake
$ cmake ../cpp -DClangTools_PATH=~/tools/bin/
...snip...
-- clang-tidy found at /home/user/tools/bin/clang-tidy
-- clang-format found at /home/user/tools/bin/clang-format
...snip...

为了使代码风格检查对每个人来说更具可重复性,我们提供了一个 docker-compose 目标,它可以从存储库的根目录执行

$ docker-compose run ubuntu-lint

或者,在打开的拉取请求上,注释机器人可以为您格式化 C++ 代码(它会将一个提交推送到分支,然后可以拉取该提交)。只需评论以下内容

@github-actions autotune

使用 include-what-you-use (IWYU) 清理包含文件#

我们偶尔会使用 Google 的 include-what-you-use 工具(也称为 IWYU)来删除不必要的导入。

要开始使用 IWYU,您必须首先按照项目文档中的说明构建它。一旦 include-what-you-use 可执行文件位于您的 $PATH 中,您必须在新的源外 CMake 构建目录中使用 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 运行 CMake,如下所示

mkdir -p $ARROW_ROOT/cpp/iwyu
cd $ARROW_ROOT/cpp/iwyu
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
  -DARROW_BUILD_BENCHMARKS=ON \
  -DARROW_BUILD_BENCHMARKS_REFERENCE=ON \
  -DARROW_BUILD_TESTS=ON \
  -DARROW_BUILD_UTILITIES=ON \
  -DARROW_COMPUTE=ON \
  -DARROW_CSV=ON \
  -DARROW_DATASET=ON \
  -DARROW_FILESYSTEM=ON \
  -DARROW_FLIGHT=ON \
  -DARROW_GANDIVA=ON \
  -DARROW_HDFS=ON \
  -DARROW_JSON=ON \
  -DARROW_PARQUET=ON \
  -DARROW_S3=ON \
  -DARROW_WITH_BROTLI=ON \
  -DARROW_WITH_BZ2=ON \
  -DARROW_WITH_LZ4=ON \
  -DARROW_WITH_SNAPPY=ON \
  -DARROW_WITH_ZLIB=ON \
  -DARROW_WITH_ZSTD=ON \
  ..

为了让 IWYU 在代码库中的所需组件上运行,必须通过 CMake 配置标志启用它。完成此操作后,您可以通过运行辅助 iwyu.sh 脚本来对整个代码库运行 IWYU

IWYU_SH=$ARROW_ROOT/cpp/build-support/iwyu/iwyu.sh
./$IWYU_SH

由于这非常耗时,您可以使用特殊的“match”选项检查与某些字符串模式匹配的子集文件

./$IWYU_SH match $PATTERN

例如,如果您想对 src/arrow/array 中的所有文件进行 IWYU 检查,您可以运行

./$IWYU_SH match arrow/array

检查 ABI 和 API 稳定性#

要构建 ABI 兼容性报告,您需要安装两个工具 abi-dumperabi-compliance-checker

在调试模式下构建 Arrow C++,或者您可以使用 -Og,它也使用必要的符号构建,但包含一些代码优化。构建完成后,您可以使用以下命令生成 ABI 报告

abi-dumper -lver 9 debug/libarrow.so -o ABI-9.dump

上面的版本号可以自由选择。由于我们希望比较版本,因此您现在应该 git checkout 您想要比较的版本,并使用不同的版本号重新运行上述命令。生成两个报告后,您可以使用以下命令构建比较报告

abi-compliance-checker -l libarrow -d1 ABI-PY-9.dump -d2 ABI-PY-10.dump

然后,报告作为 HTML 生成在 compat_reports/libarrow 中。

API 文档#

我们在头文件中使用 Doxygen 样式注释 (///) 用于我们希望在类和函数的 API 文档中显示的注释。

在使用 clang 并使用 -DBUILD_WARNING_LEVEL=CHECKIN 构建时,将使用 -Wdocumentation 标志,该标志检查一些常见的文档不一致,例如用 \param 记录一些函数参数,但不是所有参数。有关此方面的更多信息,请参阅 LLVM 文档警告部分

虽然我们在主要的基于 Sphinx 的文档站点中发布了 API 文档,但您也可以随时使用 Doxygen 构建 C++ API 文档。从 cpp/apidoc 目录运行以下命令

doxygen Doxyfile

这需要安装 Doxygen

Apache Parquet 开发#

要构建用于 Apache Parquet 的 C++ 库,在调用 CMake 时添加标志 -DARROW_PARQUET=ON。要使用加密支持构建 Apache Parquet,在调用 CMake 时添加标志 -DPARQUET_REQUIRE_ENCRYPTION=ON。可以使用 parquet make 目标构建 Parquet 库和单元测试

make parquet

在 Linux 和 macOS 上,如果您在系统上没有安装 Apache Thrift,或者您使用 -DThrift_SOURCE=BUNDLED 构建,则必须安装 bisonflex 包。在 Windows 上,我们在从源代码构建 Thrift 时自动处理这些构建依赖项。

运行 ctest -L unittest 将运行所有构建的 C++ 单元测试,而 ctest -L parquet 将只运行 Parquet 单元测试。单元测试依赖于环境变量 PARQUET_TEST_DATA,该变量依赖于对存储库 apache/parquet-testing 的 git 子模块

git submodule update --init
export PARQUET_TEST_DATA=$ARROW_ROOT/cpp/submodules/parquet-testing/data

这里 $ARROW_ROOT 是 Arrow 代码库的绝对路径。

Arrow Flight RPC#

除了 Arrow 依赖项之外,Flight 还需要

  • gRPC (>= 1.14,大约)

  • Protobuf (>= 3.6,早期版本可能有效)

  • c-ares(gRPC 使用)

默认情况下,Arrow 将尝试在构建 Flight 时下载并构建这些依赖项。

可选的 flight 库和测试可以通过传递 -DARROW_FLIGHT=ON 来构建。

cmake .. -DARROW_FLIGHT=ON -DARROW_BUILD_TESTS=ON
make

您也可以使用现有的额外依赖项安装。构建时,设置环境变量 gRPC_ROOT 和/或 Protobuf_ROOT 和/或 c-ares_ROOT

我们正在针对最新版本的 gRPC 进行开发。从 https://forge.conda.org.cn/ 获取的 grpc-cpp 包是跨平台获取 gRPC 的一种可靠方式。您可以尝试使用 gRPC 和 Protobuf 的系统库,但这些库很可能太旧了。在 macOS 上,您可以尝试使用 Homebrew

brew install grpc