Got tired from holywars on includes order in a C++ project? With sort-cpp-includes you can end the war! sort-cpp-includes is able to sort include directories according to simple grouping rules provided by the user. You can create different rulesets for multiple projects according to the local policy.
Install for all users:
pip install sort-cpp-headers
Or install for a single user:
pip install --user sort-cpp-headers
The tool is simple to use. To sort your #include's just pass it your
compile_commands.json and paths to header files and source files:
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ...
sort-cpp-includes --compile-commands compile_commands.json src/ include/ main.cppcompile_commands.json can be generated via cmake or vscode.
After the successful run you might notice changes in your source files,
if the sorting order was not met before.
The tool comes with a simple sorting policy: pair header, C headers, C++ headers,
headers from /usr/include, the rest files. If it doesn't fit you, you may
define your own policy and pass it to sort-cpp-includes using '-d' option.
An example from Yandex.TPlatform config:
rules:
- matchers:
- virtual: "@pair"
- matchers:
- virtual: "@std-c"
- matchers:
- virtual: "@std-cpp"
- matchers:
- regex: "/usr/include/.*"
- matchers:
- regex: ".*/third_party/.*"
- regex: ".*/google-benchmark/.*"
- matchers:
- regex: ".*/userver/.*"
- matchers:
- regex: ".*/build/.*"
- matchers:
- regex: ".*/libraries/.*"
- matchers:
- regex: ".*/services/.*"The sorting and grouping runs in 2 steps. First, the include group is calculated. Adjacent include groups will be separated with a single empty line. Second, the sorting takes place for each group, independently. Each matcher define a sort group. It may consist of one or more matchers. For now the following matchers are implemented:
- regex - a simple Python's
rematcher - virtual: @pair - the pair header (
server.hppforserver.cpp) - virtual: @std-c - standard C language headers
- virtual: @std-cpp - standard C++ language headers (C++17)
You may add several matchers to the same group, it would mean "at least one matcher from the group must match". The first match wins, IOW, if a first group matcher matches the include, the rest groups are skipped.
To properly split includes into groups separated by newlines, we have to know
the full paths of the included header files. The full path is used to identify
an include group according to the user policy. E.g. #include <os.hpp> may include
$PWD/os.hpp, /usr/include/os.hpp, and so on. sort-cpp-includes doesn't
resolve includes by itself, it uses a C++ compiler's ability to preprocess
your source files.
- Sourceless header files: you have to include each header into matched .cpp files at least once.
sort-cpp-includeswas tested on clang only, so sorting with alternative compilers might not work as expected.- Only a single thread is used, but we could utilize more
sort-cpp-includesstops searching include directives on the first non-include line except#pragma once.