Skip to content

dt-bindings: automated coding style check for DTS examples

Daniel Golle linux-devicetree linux-kbuild lkml 5 versions – Applied

Status from this message: Applied, thanks!

Get series with b4
b4 am [email protected]

Versions newest first · linked by author and title

  1. v5 Latest4 patches 5 repliesApplied
  2. v43 patches 0 repliesSuperseded
  3. v33 patches 0 repliesSuperseded
Earlier versions · 2
VersionPostedPatchesRepliesStatus
v23 patches7 repliesSuperseded
v12 patches2 repliesSuperseded

Changes in v5 from the cover letter

- dt-check-style: parser robustness fixes from a sashiko.dev AI review (multi-line CPP macros, "/* ... */ code" on one line, "}; };" depth tracking, malformed unit addresses, labels inside strings and on digit-leading node names, unclosed /* on PROPERTY lines)
- dt-check-style: new relaxed-mode rule unclosed-block-comment
- new patch: scripts/jobserver-exec propagates child exit status (prereq so chk_style errors stay reported)
- selftest: add fixtures covering the parser fixes
- selftest: move SPDX header to "// SPDX-..." on line 1 in the three .dts fixtures (checkpatch)

Patches in v5 Applied

#Subject and filesSizeRepliesApplied
1/4dt-bindings: add DTS style checkerscripts/dtc/dt-check-style+1192 -01 reply
2/4scripts/jobserver-exec: propagate child exit statusscripts/jobserver-exec+2 -22 replies
3/4dt-bindings: wire style checker into dt_binding_checkDocumentation/devicetree/bindings/Makefile+17 -21 reply
4/4dt-bindings: add self-test fixtures for style checkerMakefile scripts/dtc/dt-style-selftest/bad/dts-spaces.dts scripts/dtc/dt-style-selftest/bad/yaml-child-addr-order.yaml +51 more+1003 -00 replies

Reviews trailers per patch

2 of 4 patches have a Reviewed-by or Acked-by.

PatchKrzysztof KozlowskiNicolas Schier
1/4R-b
2/4R-b R-b
3/4
4/4

Trailers given in replies are filled; those carried in the patches from earlier versions are outlined with dashes.

Read the v5 thread

Cover letter [PATCH v5 0/4] dt-bindings: automated coding style check for DTS examples

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, unclosed /* block comments, 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; no whitespace padding 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/[email protected]/
v2: https://lore.kernel.org/all/[email protected]/
v3: https://lore.kernel.org/all/[email protected]/
v4: https://lore.kernel.org/all/[email protected]/

Changes since v4:
- dt-check-style: parser robustness fixes from a sashiko.dev AI review (multi-line CPP macros, "/* ... */ code" on one line, "}; };" depth tracking, malformed unit addresses, labels inside strings and on digit-leading node names, unclosed /* on PROPERTY lines)
- dt-check-style: new relaxed-mode rule unclosed-block-comment
- new patch: scripts/jobserver-exec propagates child exit status (prereq so chk_style errors stay reported)
- selftest: add fixtures covering the parser fixes
- selftest: move SPDX header to "// SPDX-..." on line 1 in the three .dts fixtures (checkpatch)

Changes since v3:
- dt-check-style: accept node and property names that begin with a digit (the DT spec permits names like 1wire@10)
- dt-check-style: strip trailing // and /* */ comments before line classification, so a trailing comment on a node-open or property line no longer causes misclassification
- dt-check-style: continuation-alignment compares display columns (tabs expanded to 8) instead of raw string length, removing many false positives on tab-indented .dts files
- dt-check-style: value-whitespace flags only whitespace directly inside the brackets (after '<', before '>'), on single- and multi-line cell lists; it no longer flags inter-value spacing, which is often deliberate column alignment
- Makefile: build the @argfile with mktemp and remove it, so no stale .tmp_.dt-style.checked is left in the build tree
- run.sh: drop bash-only process substitution (POSIX sh now) and check the checker's exit status
- selftest: add fixtures for the above (digit-leading nodes, trailing comments, multi-line cell arrays, tab+space aligned continuations) and update yaml-value-ws for the reworked value-whitespace rule

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 3/4 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.

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

rule yaml dts
property-order 14554 245000

  continuation-alignment   1857    93536
  indent-consistent        1562    48720
  required-blank-lines     1876    48563
  line-length               105    26322
  child-name-order          667    16821
  mixed-indent-chars          0    13294
  unused-labels            3611    11628
  child-address-order        63     4076
  blank-lines                82     1866
  node-close-alone           38      774
  value-whitespace           38      715
  hex-case                   78      669
  indent-unit-dts            --      190
  unit-address-format         5       39
  trailing-whitespace         0       10
  indent-unit-strict       1492       --
  indent-unit               179       --

(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.

Daniel Golle (4):
dt-bindings: add DTS style checker scripts/jobserver-exec: propagate child exit status
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                    | 1192 +++++++++++++++++
 .../dtc/dt-style-selftest/bad/dts-spaces.dts  |   12 +
 .../bad/yaml-child-addr-order.yaml            |   41 +
 .../bad/yaml-child-name-order.yaml            |   37 +
 .../bad/yaml-cont-align.yaml                  |   30 +
 .../bad/yaml-digit-node-order.yaml            |   37 +
 .../dt-style-selftest/bad/yaml-hex-case.yaml  |   29 +
 .../bad/yaml-indent-strict.yaml               |   29 +
 .../bad/yaml-label-in-string.yaml             |   30 +
 .../bad/yaml-line-length.yaml                 |   29 +
 .../bad/yaml-mixed-indent.yaml                |   29 +
 .../bad/yaml-multi-close.yaml                 |   35 +
 .../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-comment.yaml            |   26 +
 .../bad/yaml-trailing-ws.yaml                 |   29 +
 .../bad/yaml-unclosed-comment.yaml            |   30 +
 .../bad/yaml-unit-addr-prefix.yaml            |   29 +
 .../dt-style-selftest/bad/yaml-unit-addr.yaml |   29 +
 .../bad/yaml-unused-label.yaml                |   29 +
 .../bad/yaml-value-ws-multiline.yaml          |   27 +
 .../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-digit-node-order.yaml.txt   |    2 +
 .../expected/yaml-hex-case.yaml.txt           |    2 +
 .../expected/yaml-indent-strict.yaml.txt      |    2 +
 .../expected/yaml-label-in-string.yaml.txt    |    2 +
 .../expected/yaml-line-length.yaml.txt        |    2 +
 .../expected/yaml-mixed-indent.yaml.txt       |    3 +
 .../expected/yaml-multi-close.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-comment.yaml.txt   |    2 +
 .../expected/yaml-trailing-ws.yaml.txt        |    2 +
 .../expected/yaml-unclosed-comment.yaml.txt   |    2 +
 .../expected/yaml-unit-addr-prefix.yaml.txt   |    2 +
 .../expected/yaml-unit-addr.yaml.txt          |    2 +
 .../expected/yaml-unused-label.yaml.txt       |    2 +
 .../expected/yaml-value-ws-multiline.yaml.txt |    2 +
 .../expected/yaml-value-ws.yaml.txt           |    2 +
 .../dt-style-selftest/good/dts-cont-align.dts |   26 +
 .../dtc/dt-style-selftest/good/dts-tab.dts    |   29 +
 .../dt-style-selftest/good/yaml-4space.yaml   |   41 +
 .../good/yaml-tricky-parsing.yaml             |   57 +
 scripts/dtc/dt-style-selftest/run.sh          |   71 +
 scripts/jobserver-exec                        |    4 +-
 57 files changed, 2214 insertions(+), 4 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-digit-node-order.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-label-in-string.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-multi-close.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-comment.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-trailing-ws.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-unclosed-comment.yaml
 create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-unit-addr-prefix.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-multiline.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-digit-node-order.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-label-in-string.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-multi-close.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-comment.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-unclosed-comment.yaml.txt
 create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-unit-addr-prefix.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-multiline.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-cont-align.dts
 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 100644 scripts/dtc/dt-style-selftest/good/yaml-tricky-parsing.yaml
 create mode 100755 scripts/dtc/dt-style-selftest/run.sh
Signature · 1 line
2.54.0