Devicetree
 help / color / mirror / Atom feed
* [PATCH v3 0/3] dt-bindings: automated coding style check for DTS examples
@ 2026-05-10 23:58 Daniel Golle
  2026-05-10 23:58 ` [PATCH v3 1/3] dt-bindings: add DTS style checker Daniel Golle
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Daniel Golle @ 2026-05-10 23:58 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Nathan Chancellor,
	Nicolas Schier, Saravana Kannan, Daniel Golle, Miguel Ojeda,
	Masahiro Yamada, Thomas Weißschuh, Tamir Duberstein,
	Steven Rostedt, Aleksander Jan Bajkowski, Guenter Roeck,
	Test User, devicetree, linux-kernel, linux-kbuild

Documentation/devicetree/bindings/dts-coding-style.rst documents
the style expected of DT examples and source files, but nothing
existing actually enforces it. dtc tolerates arbitrary whitespace,
yamllint only sees the YAML envelope and not the DTS content
inside literal block scalars, and so reviewers spend cycles
flagging issues that tooling could catch.

Add scripts/dtc/dt-check-style, a Python tool that checks DTS
coding style on YAML binding examples and on .dts/.dtsi/.dtso
source files. Rules live in a small declarative registry; each
rule is tagged 'relaxed' (default) or 'strict' (opt-in for new
submissions). Promoting a rule from strict to relaxed is a
one-line edit once the tree catches up.

Relaxed mode covers trailing whitespace, tab characters in YAML
examples, mixed tab+space indents, and the per-input-type indent
character (1 tab for .dts/.dtsi/.dtso). It is zero-violation on
the current tree and runs as part of dt_binding_check_one, so no
new warnings appear in `make dt_binding_check`.

Strict mode adds indent unit and depth consistency; blank-line
policy (no consecutive blanks or blanks at body edges; required
blank line before each child node and before "status"); property
ordering by canonical bucket (compatible, reg/reg-names, ranges,
standard, vendor, status) with declarative within-bucket pairing
rules (<x>-names follows <x>, pinctrl-names follows the last
pinctrl-N) and natural-sort fallback; sibling node ordering by
unit address or natural-sort name; line length (80 columns);
continuation alignment of multi-line property values under the
first '<' or '"' after the '='; lowercase hex literals and unit
addresses; single-spaced values inside <...>; closing-brace
placement; and unused-label detection (skipped for .dtsi/.dtso
since labels there are exported to includers/applies-to).
Together these constrain a DT structure to a single canonical
rendering modulo the author's choice of when to wrap properties
for readability. Comments are intentionally out of scope. Strict
mode is opt-in, intended for use by checkpatch.pl in a follow-up
series.

The tool reads file paths from @argfile and parallelises across
CPUs via -j N. With no -j given it picks up $PARALLELISM (set by
scripts/jobserver-exec from the GNU make jobserver) and falls
back to os.cpu_count() otherwise. Running as one Python
invocation amortises the ruamel.yaml import across the whole
tree -- ~2s on a 32-CPU host vs ~28s sequential. ruamel.yaml is
the only non-stdlib dependency, already required by dtschema.

A selftest under scripts/dtc/dt-style-selftest/ pairs good/ and
bad/ fixtures with expected output so rule behaviour can be
exercised independently of the full tree via the
dt_style_selftest top-level make target.
---
v1: https://lore.kernel.org/all/cover.1776700167.git.daniel@makrotopia.org/
v2: https://lore.kernel.org/all/cover.1777471439.git.daniel@makrotopia.org/

Changes since v2:
 - route findings to stderr so a quiet dt_binding_check produces
   no output (Rob)
 - switch the Makefile recipe from mktemp to Kbuild's
   $(tmp-target) so build output stays inside the build folder
   (Nathan)
 - collapse the recipe's exit-handling tail into the familiar
   "&& touch $@ || true" pattern, matching cmd_chk_bindings;
   keeps future warnings non-fatal (Rob, Nathan)
 - explain in patch 2/3 why the recipe uses an explicit
   $(PYTHON3) prefix where the neighbouring recipes call their
   scripts directly (Rob)
 - append a trailing newline to every expected/*.txt selftest
   fixture (Rob)
 - restore the trailing whitespace inside yaml-trailing-ws.yaml
   that had been silently stripped during re-application, so the
   selftest actually exercises the trailing-whitespace rule

Changes since v1:
 - rules declared in a registry tagged relaxed/strict; default
   relaxed mode is zero-violation on the current tree
 - tool now also accepts .dts/.dtsi/.dtso files directly (with a
   tab-indent variant); unused-labels skipped for .dtsi/.dtso
   where labels are exported to includers/applies-to
 - renamed dt-check-example-style -> dt-check-style
 - added -j N with $PARALLELISM (jobserver) awareness
 - dropped node-name [a-z0-9-] check (Rob: better as a meta-schema)
 - property-order rebuilt around buckets + declarative pairing
   rules plus natural-sort fallback
 - added child-name-order, required-blank-lines, hex-case,
   unit-address-format, value-whitespace, node-close-alone,
   line-length and continuation-alignment to strict mode
 - new selftest patch (Krzysztof: "would be happy to see at
   least a few test cases for it")

Default relaxed mode is zero-violation on the current tree once
the small prep-cleanup series [1] has landed.

Strict-mode violation counts on a current tree (5506 YAML
bindings, 6530 in-tree .dts/.dtsi/.dtso under arch/):

  rule                         yaml      dts
  property-order              14457   240804
  indent-consistent            2435   294778
  continuation-alignment       2462   187914
  unused-labels                3611    11628
  required-blank-lines         1862    47351
  line-length                   102    25999
  child-name-order              664    16409
  mixed-indent-chars              0    13275
  indent-unit-strict           1493       --
  child-address-order            69     4075
  blank-lines                    91     1963
  value-whitespace               87      983
  node-close-alone               40      783
  hex-case                       78      666
  indent-unit                   181       --
  indent-unit-dts                --      202
  unit-address-format             5       39
  trailing-whitespace             0       10

(YAML and DTS columns reflect the rules that apply to each input
type; e.g. indent-unit-strict is YAML-only since .dts files use
tabs, indent-unit-dts is the equivalent DTS-only check.
unused-labels is skipped for .dtsi/.dtso since labels there are
exported to includers/applies-to.)

The script was written with generous help from Claude Opus 4.7,
since my Python is even worse than my DTS coding style.

[1] https://lore.kernel.org/all/cover.1777434096.git.daniel@makrotopia.org/

Daniel Golle (3):
  dt-bindings: add DTS style checker
  dt-bindings: wire style checker into dt_binding_check
  dt-bindings: add self-test fixtures for style checker

 Documentation/devicetree/bindings/Makefile    |   19 +-
 Makefile                                      |    6 +
 scripts/dtc/dt-check-style                    | 1063 +++++++++++++++++
 .../dtc/dt-style-selftest/bad/dts-spaces.dts  |   13 +
 .../bad/yaml-child-addr-order.yaml            |   41 +
 .../bad/yaml-child-name-order.yaml            |   37 +
 .../bad/yaml-cont-align.yaml                  |   30 +
 .../dt-style-selftest/bad/yaml-hex-case.yaml  |   29 +
 .../bad/yaml-indent-strict.yaml               |   29 +
 .../bad/yaml-line-length.yaml                 |   29 +
 .../bad/yaml-mixed-indent.yaml                |   29 +
 .../bad/yaml-node-close.yaml                  |   31 +
 .../bad/yaml-prop-order.yaml                  |   29 +
 .../bad/yaml-prop-pairing.yaml                |   33 +
 .../bad/yaml-required-blank.yaml              |   33 +
 .../dtc/dt-style-selftest/bad/yaml-tab.yaml   |   29 +
 .../bad/yaml-trailing-ws.yaml                 |   29 +
 .../dt-style-selftest/bad/yaml-unit-addr.yaml |   29 +
 .../bad/yaml-unused-label.yaml                |   29 +
 .../dt-style-selftest/bad/yaml-value-ws.yaml  |   29 +
 .../expected/dts-spaces.dts.txt               |    2 +
 .../expected/yaml-child-addr-order.yaml.txt   |    2 +
 .../expected/yaml-child-name-order.yaml.txt   |    2 +
 .../expected/yaml-cont-align.yaml.txt         |    2 +
 .../expected/yaml-hex-case.yaml.txt           |    2 +
 .../expected/yaml-indent-strict.yaml.txt      |    2 +
 .../expected/yaml-line-length.yaml.txt        |    2 +
 .../expected/yaml-mixed-indent.yaml.txt       |    3 +
 .../expected/yaml-node-close.yaml.txt         |    2 +
 .../expected/yaml-prop-order.yaml.txt         |    2 +
 .../expected/yaml-prop-pairing.yaml.txt       |    3 +
 .../expected/yaml-required-blank.yaml.txt     |    3 +
 .../expected/yaml-tab.yaml.txt                |    2 +
 .../expected/yaml-trailing-ws.yaml.txt        |    2 +
 .../expected/yaml-unit-addr.yaml.txt          |    2 +
 .../expected/yaml-unused-label.yaml.txt       |    2 +
 .../expected/yaml-value-ws.yaml.txt           |    2 +
 .../dtc/dt-style-selftest/good/dts-tab.dts    |   30 +
 .../dt-style-selftest/good/yaml-4space.yaml   |   41 +
 scripts/dtc/dt-style-selftest/run.sh          |   67 ++
 40 files changed, 1769 insertions(+), 2 deletions(-)
 create mode 100755 scripts/dtc/dt-check-style
 create mode 100644 scripts/dtc/dt-style-selftest/bad/dts-spaces.dts
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-child-addr-order.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-child-name-order.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-cont-align.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-hex-case.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-indent-strict.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-line-length.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-mixed-indent.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-node-close.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-prop-order.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-prop-pairing.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-required-blank.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-tab.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-trailing-ws.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-unit-addr.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-unused-label.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-value-ws.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/expected/dts-spaces.dts.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-child-addr-order.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-child-name-order.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-cont-align.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-hex-case.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-indent-strict.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-line-length.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-mixed-indent.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-node-close.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-prop-order.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-prop-pairing.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-required-blank.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-tab.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-trailing-ws.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-unit-addr.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-unused-label.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-value-ws.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/good/dts-tab.dts
 create mode 100644 scripts/dtc/dt-style-selftest/good/yaml-4space.yaml
 create mode 100755 scripts/dtc/dt-style-selftest/run.sh

-- 
2.54.0

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-05-10 23:59 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-10 23:58 [PATCH v3 0/3] dt-bindings: automated coding style check for DTS examples Daniel Golle
2026-05-10 23:58 ` [PATCH v3 1/3] dt-bindings: add DTS style checker Daniel Golle
2026-05-10 23:58 ` [PATCH v3 2/3] dt-bindings: wire style checker into dt_binding_check Daniel Golle
2026-05-10 23:59 ` [PATCH v3 3/3] dt-bindings: add self-test fixtures for style checker Daniel Golle

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox