编码指南

目录

C++ 编码指南

  • 遵循Google C++ 风格指南,有两个例外

    • 每行文本最多包含 100 个字符。

    • 允许使用 C++ 异常。

  • 使用 C++17 特性,例如智能指针、大括号初始化器、lambda 函数和 std::thread

  • 使用 Doxygen 文档化所有接口代码。

  • 我们对头文件导入的符号有一些注释,其中一些由 include-what-you-use 提示。这不是必需的。

  • 我们使用 clang-tidy 和 clang-format。您可以在 XGBoost 源码树的根目录中查看它们的配置。

  • 我们有一系列自动化检查,以确保我们的所有代码库符合 Google 风格。在提交拉取请求之前,建议您在本地机器上运行风格检查。请参阅 R 编码指南

Python 编码指南

R 编码指南

代码风格

  • 对于 C++ 代码,我们遵循 Google 的 C++ 风格指南。

    • 这主要是为了与项目的其余部分保持一致。

    • 另一个原因是我们可以使用 linter 自动检查风格。

  • 必要时,您可以使用 // NOLINT(*) 注释禁用特定行的 linter 警告。

  • 我们使用 roxygen 文档化 R 包。

Rmarkdown 插图教程

Rmarkdown 插图教程位于 R-package/vignettes 中。这些 Rmarkdown 文件未编译。我们将编译版本托管在 doc/R-package 中。

添加新的 Rmarkdown 插图教程需要遵循以下步骤

  • 将原始 Rmarkdown 文件添加到 R-package/vignettes 中。

  • 修改 doc/R-package/Makefile,添加要构建的 markdown 文件。

  • dmlc/web-data 仓库克隆到 doc 文件夹。

  • 现在在 doc/R-package 目录下输入以下命令

    make the-markdown-to-make.md
    
  • 这将生成 markdown 文件以及 doc/web-data/xgboost/knitr 中的图表。

  • 修改 doc/R-package/index.md,使其指向生成的 markdown 文件。

  • 将生成的图表添加到 dmlc/web-data 仓库中。

    • 如果您已经将仓库克隆到 doc 目录下,这意味着执行 git add

  • 为 markdown 文件和 dmlc/web-data 创建拉取请求 (PR)。

  • 您也可以在 doc 目录下输入以下命令在本地构建文档

    make html
    

我们这样做是为了避免因生成的图像而导致仓库大小爆炸式增长。

R 包版本控制

请参阅 XGBoost 发布策略

使用不同编译器测试 R 包

您可以通过修改主目录中的配置文件来更改 R 的默认编译器。例如,如果您想在 Linux 上测试使用 clang++ 而非 g++ 构建的 XGBoost,请将以下内容放入您的 ~/.R/Makevars 文件中

CC=clang-15
CXX17=clang++-15

请注意,变量名应与 R CMD 使用的名称匹配

R CMD config CXX17

在 R 中注册原生例程

根据R 扩展手册,注册原生例程并禁用符号搜索是良好的实践。当对 R 包的 C++ 接口进行任何更改或添加时,请同时在 src/init.c 中进行相应的更改。

生成包并运行测试

XGBoost 的源码布局与正常的 R 包有些不同,因为 XGBoost 主要用 C++ 编写,同时考虑了多种语言绑定。因此,生成标准的 R tarball 需要采取一些特殊的措施。大多数测试都在 CI 上运行,因此了解其工作原理的最佳方式是查看 CI 配置文件(撰写本文时是 GitHub action)。在 ops/scriptR-package/tests/helper_scripts 中有辅助脚本,用于运行各种检查,包括 linter 和制作标准 tarball。

本地运行格式检查

一旦您向 dmlc/xgboost 提交拉取请求,我们将执行两项自动检查以强制执行编码风格规范。为了加快代码审查过程,建议您在提交拉取请求之前在本地机器上运行这些检查。

Linter

我们结合使用多种 linter 来强制执行风格规范并查找潜在错误。Linting 对于 Python 等脚本语言特别有用,因为我们可以捕获许多原本会在运行时发生的错误。

对于 Python 脚本,使用 pylintblackisort 提供编码风格指导,并且需要 mypy 进行类型检查。对于 C++,使用 cpplintclang-tidy。对于 R,使用 lintr

要在本地运行 Python 检查,请安装前面提到的检查工具并运行

cd /path/to/xgboost/
python ./ops/script/lint_python.py --fix

要运行 R 检查

cd /path/to/xgboost/
R CMD INSTALL R-package/
Rscript ops/script/lint_r.R $(pwd)

要在本地运行 cpplint 检查

cd /path/to/xgboost/
python ./ops/script/lint_cpp.py

有关 clang-tidy,请参阅下一节。对于 CMake 脚本

bash ./ops/script/lint_cmake.sh

最后,jvm 包的 linter 已集成到 maven 构建过程中。

Clang-tidy

Clang-tidy 是一个由 LLVM 团队开发的 C++ 代码高级 linter。我们使用它来使我们的 C++ 代码库符合现代 C++ 实践和约定。

要在本地运行此检查,请在顶级源码树中运行以下命令

cd /path/to/xgboost/
python3 ops/script/run_clang_tidy.py

此外,该脚本接受两个可选的整数参数:--cpp--cuda。默认情况下,它们都设置为 1,表示将同时检查 C++ 和 CUDA 代码。如果您的机器上未安装 CUDA 工具包,将会遇到错误。要从 linting 中排除 CUDA 源码,请使用

cd /path/to/xgboost/
python3 ops/script/run_clang_tidy.py --cuda=0

类似地,如果您想从 linting 中排除 C++ 源码

cd /path/to/xgboost/
python3 ops/script/run_clang_tidy.py --cpp=0

用户输入数据处理指南

这是一份关于处理用户输入数据的非全面指南。XGBoost 本身支持多种数据结构,它们大多来自更高级的语言绑定。输入范围从基本的连续一维内存缓冲区到更复杂的数据结构,例如带有有效性掩码的列式数据。原始输入数据可以在两个地方使用:首先是构建各种 DMatrix,其次是原地预测。对于纯内存缓冲区,由于它只是一个带有大小的指针,所以没有太多可讨论的。但对于一般的 n 维数组和列式数据,存在许多细微之处。XGBoost 有 3 种不同的数据结构用于处理可选掩码数组(张量),对于消费用户输入,应选择 ArrayInterface。由于历史原因(XGBoost 起初是一个简单得多的库,当时不太关心内存使用),许多现有函数只接受纯指针。ArrayInterface 是 numpy 定义的 __array_interface__ 协议或 numba 定义的 __cuda_array_interface__ 的内存表示。以下是接受相关用户输入时需要牢记的检查清单

  • [ ] 它是否是跨步的?(由 strides 字段标识)

  • [ ] 如果它是一个向量,它是行向量还是列向量?(由 shapestrides 共同标识)

  • [ ] 数据类型是否支持?半精度类型和 128 位整数类型在进入 XGBoost 之前应进行转换。

  • [ ] 它是否具有高于 1 的维度?(由 shape 字段标识)

  • [ ] 是否有一些维度是平凡的?(shape[dim] <= 1)

  • [ ] 它是否有掩码?(由 mask 字段标识)

  • [ ] 掩码是否可以广播?(目前不支持)

  • [ ] 它是否在 CUDA 内存上?(由 data 字段以及可选的 stream 标识)

大多数检查在构建 ArrayInterface 时处理,但数据类型问题除外,因为它不知道如何将这些指针转换为 C 内置类型。但为了安全起见,仍应尝试为所有条目编写相关测试。数据类型问题应在每种特定数据输入的语言绑定中处理。对于单块列式格式,它只是每列的掩码数组,因此应统一视为普通数组。对于输入预测器 X,我们为每种输入类型提供了适配器。有些是其他适配器的组合。例如,CSR 矩阵有 3 个潜在的跨步数组,分别用于 indptrindicesvalues。不应对这些组件做任何假设(应考虑所有检查项)。对 CSR 矩阵的行进行切片时,应根据各自的步长计算每个字段的偏移量。

对于标签等元信息(其大小和复杂性都在增长),目前我们只接受掩码数组(没有专门的适配器)。应注意输入数据的形状。对于基础边距 (base margin),如果将来有多个目标,它可能是 2 维或更高维。目前 DMatrix 中的 getter 只返回一维扁平向量,这可以在将来需要时改进。