如何以 clang 格式为外部标头创建类别

How to create category for external headers in clang-format?

本文关键字:创建 外部 clang 格式      更新时间:2023-10-16

我想配置 clang 格式以C++包含的标头进行排序,如下所示:

  • 主标头(与当前 cpp 文件相关联(,
  • 通过 " 包含的本地标头,
  • 通过<>包含的其他标头,
  • 来自特定外部库的标头(例如 boost、catch2(,
  • 系统/标准标头。

我在 macOS 上使用 clang 格式的 8.0.0。我当前的配置(仅与包含相关的代码片段(如下:

SortIncludes: true
IncludeBlocks: Regroup
IncludeCategories:
  # Headers in <> without extension.
  - Regex:           '<([A-Za-z0-9/-_])+>'
    Priority:        4
  # Headers in <> from specific external libraries.
  - Regex:           '<((bboostb)|(bcatch2b))/([A-Za-z0-9./-_])+>'
    Priority:        3
  # Headers in <> with extension.
  - Regex:           '<([A-Za-z0-9./-_])+>'
    Priority:        2
  # Headers in "" with extension.
  - Regex:           '"([A-Za-z0-9./-_])+"'
    Priority:        1

在此配置中,我假设系统/标准标头没有扩展名。它不适用于 UNIX/POSIX 标头。自动检测主标头并分配优先级 0。到目前为止,除了外部库的类别外,一切似乎都按预期工作。看起来 clang 格式将其分配给优先级 2。

预期成果:

#include "test.h"
#include <allocator/region.hpp>
#include <page.hpp>
#include <page_allocator.hpp>
#include <test_utils.hpp>
#include <utils.hpp>
#include <zone_allocator.hpp>
#include <catch2/catch.hpp>     // <--------
#include <array>
#include <cmath>
#include <cstring>
#include <map>

实际结果:

#include "test.h"
#include <allocator/region.hpp>
#include <catch2/catch.hpp>     // <--------
#include <page.hpp>
#include <page_allocator.hpp>
#include <test_utils.hpp>
#include <utils.hpp>
#include <zone_allocator.hpp>
#include <array>
#include <cmath>
#include <cstring>
#include <map>

如何配置优先级 3 以获得预期的结果?

我通过使用和修改此选项的 clang 格式文档中的示例来让它工作:

SortIncludes: true
IncludeBlocks: Regroup
IncludeCategories:
  # Headers in <> without extension.
  - Regex:           '<([A-Za-z0-9Q/-_E])+>'
    Priority:        4
  # Headers in <> from specific external libraries.
  - Regex:           '<(catch2|boost)/'
    Priority:        3
  # Headers in <> with extension.
  - Regex:           '<([A-Za-z0-9.Q/-_E])+>'
    Priority:        2
  # Headers in "" with extension.
  - Regex:           '"([A-Za-z0-9.Q/-_E])+"'
    Priority:        1

特别是,我将优先级 3 正则表达式更改为更像原始示例:

'^(<|"(gtest|gmock|isl|json)/)'

此外,我添加了 \Q 和 \E 修饰符以避免 Julio 提到的问题。现在一切都按预期工作。但是我仍然不知道为什么问题帖子中的解决方案不起作用。

问题是Clan格式使用POSIX ERE正则表达式。这些不支持单词边界。

所以<catch2/catch.hpp>永远无法匹配第二条规则。然后,为匹配的第三个规则计算相同的字符串。

如果它符合第二条规则,它就会停在那里,但由于它没有,它继续下一个规则。

只需删除正则表达式上的所有b即可。删除它们是安全的,因为您已经有单词边界:在左侧你有<,在右侧你有/所以即使你可以使用单词boudaries,它也毫无用处。

  - Regex:           '<(boost|catch2)/([A-Za-z0-9./-_])+>'
    Priority:        3

注意:请记住,[]内部的-应用反斜杠转义,除非将其放置在最后一个位置。那是因为它用于范围。所以当你写[A-Za-z0-9./-_]时,你的意思是A-Za-z0-9.或范围从/_,你可能不是故意的。

如果您遵循将所有外部标头放在 <> 中并将本地标头放在 "" 中的约定,则可以使用以下配置文件。它将根据标题的类别对标题进行很好的排序:

.clang-format

SortIncludes: CaseSensitive
IncludeBlocks: Regroup
IncludeCategories:
  # Specific external headers in <> to put first
  - Regex: '<(catch2|gtest).*>'
    Priority: 1
  # External headers in <> with extension or /
  - Regex: '<[-w/-_]+[./][-w/-_]+>'
    Priority: 2
  # Standard headers in <>
  - Regex: '<[-w/-_]+>'
    Priority: 3
  # Local headers in ""
  - Regex: '"[-w/-_]*"'
    Priority: 4

这将像这样对包含进行排序:

#include <catch2/catch_test_macros.hpp>
#include <Eigen/Core>
#include <fmt/format.h>
#include <yaml-cpp/yaml.h>
#include <algorithm>
#include <cmath>
#include <concepts>
#include <filesystem>
#include "../some_other_local_header"
#include "./some_local_header.hpp"