In [RFC] Having an auto-formatter for CMake @Sukumarsawant raised the idea of a CMake formatter for all of LLVM, but there wasn’t concensus to proceed. However, I still want one and figured that we could start with our project.
This weekend I spent time creating a formatter that would handle the non-controversial items. If we accept this, I would get it checked it and run as part of the formatting presubmit GitHub action.
These are the formatting rules I went with, based on my observation of LLVM libc (and taking a glance at the rest of the LLVM project so that we don’t gratuitously deviate)
- Command Casing: Built-in language commands cased in lowercase (
add_entrypoint_object,set,if); module commands (likeExternalProject_Add) and custom functions retain canonical/declared casing. - Parenthesis Spacing: No space between command name and opening
(. Collapses multiple spaces between arguments down to a single space. - Quoted String Immutability: Quoted arguments (
"...") and bracket arguments ([=[...]=]) are single immutable AST tokens. Multi-line quoted strings are preserved 100% untouched. - Empty Closures:
endif(),else(),endfunction(),endmacro(),endforeach(),endwhile(). - Schema-Aware Keyword Casing: Keywords in command schema upper-cased; positional args, function parameters & file paths untouched.
- Multi-line Argument Layout: Keywords and positional args indented +2 spaces relative to call base; multi-value list items indented +4 spaces; closing
)at +0 spaces. - Control Block Indentation: 2-space indentation inside
if/foreach/function/macro. - Comment Formatting: Line comments buffer and align with the indentation level of the code element immediately following them, unless separated by a blank line (standalone comments) or immediately preceding a closing parenthesis
). - Cleanliness: Trailing whitespace stripped, single trailing newline for non-empty files; empty files preserved 0-byte.
Here’s a branch with the resulting formatter run:
There are two areas that are not formatted correctly right now (hopefully. I’ve stared at the diff too long and might miss things). In both of these cases, I am inclined to change the source rather than the formatter:
- Multi-line trailing quote:
Foo bar baz # This is a trailing quote
# that spans multiple lines.
Previously we had space aligned the two comments. However, semantically, there is no way to tell whether the second line is a continuation or whether it’s a comment on the following item. The correct thing here is to make it a multi-line quote before the Foo bar baz line.
- Variables at the end of multi-value lists:
add_header_library(
scanf_config
HDRS
scanf_config.h
${scanf_config_copts}
)
There is no way to tell whether or not ${scanf_config_copts} should be part of HDRS or should be an ARGN value of add_header_library. In this case, I will add a comment to these # ARGN that will both tell the human and the formatter that this isn’t intended to be part of HDRS.
I am intentionally not sharing the formatter yet, because it’s definitely not polished at all =) But it’s in Python and I would provide unit tests, etc. for it. It doesn’t rely on anything from PIP so doesn’t require new things on people’s workstations or the buildbots to incorporate as part of their flow.
Tks,
Jeff Bailey