英语

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。

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

clang-format 也支持读取统一差异,因此您可以轻松地审查补丁和 git 差异。请参阅以下文档:

要避免 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)。

  • 排序 #includesSortIncludes)。

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