英语

clang-format

clang-format 是一个根据一组规则和启发式方法格式化 C/C++/... 代码的工具。像大多数工具一样,它不是完美的,也不能涵盖所有情况,但它足以提供帮助。

clang-format 可以用于以下几个目的:

  • 快速将代码块重新格式化为内核风格。在移动代码和对齐/排序时特别有用。参见 clangformatreformat

  • 发现您维护的文件、您审查的补丁、差异等中的样式错误、错别字和可能的改进。参见 clangformatreview

  • 帮助您遵循编码风格规则,对于那些刚接触内核开发或同时在具有不同编码风格的多个项目中工作的人来说特别有用。

它的配置文件是内核树根目录中的 .clang-format。其中包含的规则试图近似最常见的内核编码风格。它们还尝试尽可能地遵循 Documentation/process/coding-style.rst。由于并非所有内核都遵循相同的风格,因此您可能想要调整特定子系统或文件夹的默认设置。为此,您可以通过在子文件夹中编写另一个 .clang-format 文件来覆盖默认设置。

该工具本身早已包含在流行的 Linux 发行版的存储库中。在您的存储库中搜索 clang-format。否则,您可以下载预构建的 LLVM/clang 二进制文件或从以下网址构建源代码:

有关该工具的更多信息,请参见:

检查文件和补丁的编码风格

通过以行内模式运行该工具,您可以检查整个子系统、文件夹或单个文件中的代码风格错误、错别字或改进。

为此,您可以运行类似以下内容:

# Make sure your working directory is clean!
clang-format -i kernel/*.[ch]

然后查看 git diff。

计算此类 diff 的行数也有助于改进/调整配置文件中的样式选项;以及测试新的 clang-format 功能/版本。

clang-format 还支持读取统一差异,因此您可以轻松地查看补丁和 git diff。参见以下文档:

要避免 clang-format 格式化文件的某些部分,您可以执行以下操作:

int formatted_code;
// clang-format off
    void    unformatted_code  ;
// clang-format on
void formatted_code_again;

虽然很想使用它来使文件始终与 clang-format 同步,特别是如果您正在编写新文件或者您是维护者,但请注意,人们可能正在运行不同的 clang-format 版本或者根本没有该工具。因此,您可能应该避免在内核源代码中使用它;至少在我们看到 clang-format 变得普遍之前。

重新格式化代码块

通过与您的文本编辑器集成,您可以通过一次击键重新格式化任意代码块(选定部分)。这在移动代码、处理深度缩进的复杂代码、多行宏(和对齐其反斜杠)等方面特别有用。

请记住,在工具没有做到最佳效果的情况下,您可以随时在之后调整更改。但作为第一步,它非常有用。

有许多流行的文本编辑器的集成。对于某些编辑器,如 vim、emacs、BBEdit 和 Visual Studio,您可以找到内置支持。有关说明,请阅读以下网址的相应部分:

对于 Atom、Eclipse、Sublime Text、Visual Studio Code、XCode 和其他编辑器和 IDE,您应该能够找到即用型插件。

对于此用例,请考虑使用辅助 .clang-format,以便您可以调整一些选项。参见 clangformatextra

缺失的支持

clang-format 缺少对内核代码中常见的一些内容的支持。它们很容易记住,因此如果您经常使用该工具,您将很快学会避免/忽略它们。

特别是,您会注意到一些非常常见的:

  • 对齐的单行 #defines,例如:

    #define TRACING_MAP_BITS_DEFAULT       11
    #define TRACING_MAP_BITS_MAX           17
    #define TRACING_MAP_BITS_MIN           7
    

    #define TRACING_MAP_BITS_DEFAULT 11
    #define TRACING_MAP_BITS_MAX 17
    #define TRACING_MAP_BITS_MIN 7
    
  • 对齐的指定初始化器,例如:

    static const struct file_operations uprobe_events_ops = {
            .owner          = THIS_MODULE,
            .open           = probes_open,
            .read           = seq_read,
            .llseek         = seq_lseek,
            .release        = seq_release,
            .write          = probes_write,
    };
    

    static const struct file_operations uprobe_events_ops = {
            .owner = THIS_MODULE,
            .open = probes_open,
            .read = seq_read,
            .llseek = seq_lseek,
            .release = seq_release,
            .write = probes_write,
    };
    

额外的特性/选项

某些特性/样式选项默认情况下未在配置文件中启用,以最大程度地减少输出和当前代码之间的差异。换句话说,为了使差异尽可能小,从而使审查完整文件样式、差异和补丁尽可能容易。

在其他情况下(例如,特定子系统/文件夹/文件),内核样式可能不同,并且启用其中一些选项可能会更好地近似那里的样式。

例如:

  • 对齐赋值 (AlignConsecutiveAssignments)。

  • 对齐声明 (AlignConsecutiveDeclarations)。

  • 重排注释中的文本 (ReflowComments)。

  • 排序 #includes (SortIncludes)。

它们通常对于块重新格式化很有用,而不是完整文件。您可能想要创建另一个 .clang-format 文件,并从您的编辑器/IDE 中使用该文件。