[libc-commits] [libc] f72b2a3 - [libc][CI] Add CMake format check to code-format-helper (#228526)

via libc-commits libc-commits at lists.llvm.org
Fri Oct 9 00:20:07 PDT 2026


Author: Jeff Bailey
Date: 2026-10-09T08:19:57+01:00
New Revision: f72b2a332cdc62c87a90cf4d578872f445d2bab0

URL: https://github.com/llvm/llvm-project/commit/f72b2a332cdc62c87a90cf4d578872f445d2bab0
DIFF: https://github.com/llvm/llvm-project/commit/f72b2a332cdc62c87a90cf4d578872f445d2bab0.diff

LOG: [libc][CI] Add CMake format check to code-format-helper (#228526)

Added CMakeFormatHelper to llvm/utils/git/code-format-helper.py so the
existing GitHub Actions code formatting workflow checks modified CMake
files under libc/ using libc/utils/cmake_format.py.

When formatting issues are found, both the GitHub Actions log and the
automated pull request comment display the exact command to fix the
files in-place alongside the command to preview the diff locally.

Updated libc/utils/cmake_format.py so --dry-run --diff emits only the
unified diff on stdout and exits non-zero on lexer or file errors.

Assisted-by: Automated tooling, human reviewed.

Added: 
    

Modified: 
    libc/utils/cmake_format.py
    libc/utils/cmake_format_test.py
    llvm/utils/git/code-format-helper.py

Removed: 
    


################################################################################
diff  --git a/libc/utils/cmake_format.py b/libc/utils/cmake_format.py
index 9087bc40ce4875..bea148b3586a15 100755
--- a/libc/utils/cmake_format.py
+++ b/libc/utils/cmake_format.py
@@ -1392,7 +1392,7 @@ def process_file(
                         pass
                 print(f"Error writing file {filepath}: {e}", file=sys.stderr)
                 return None
-        elif dry_run:
+        elif dry_run and not show_
diff :
             print(f"Formatting needed: {filepath}")
 
     return has_changes
@@ -1496,6 +1496,7 @@ def main() -> None:
     pre_scan_workspace_modules(args.paths)
 
     files_needing_format = 0
+    had_errors = False
     if args.jobs > 1 and len(cmake_files) > 1:
         from concurrent.futures import ProcessPoolExecutor, as_completed
 
@@ -1520,8 +1521,11 @@ def main() -> None:
                     result = future.result()
                     if result is True:
                         files_needing_format += 1
+                    elif result is None:
+                        had_errors = True
                 except Exception as e:
                     print(f"Error processing {fpath}: {e}", file=sys.stderr)
+                    had_errors = True
     else:
         for fpath in cmake_files:
             changed = process_file(
@@ -1529,9 +1533,16 @@ def main() -> None:
             )
             if changed is True:
                 files_needing_format += 1
+            elif changed is None:
+                had_errors = True
+
+    if had_errors:
+        sys.exit(1)
 
     if args.dry_run and files_needing_format > 0:
-        print(f"\n{files_needing_format} file(s) need formatting.")
+        if not args.
diff :
+            print(f"\n{files_needing_format} file(s) need formatting.")
+            print("Run with -i / --inplace to format files in-place.")
         sys.exit(1)
 
     sys.exit(0)

diff  --git a/libc/utils/cmake_format_test.py b/libc/utils/cmake_format_test.py
index b699f1e5da9b2e..4e181a43b186b8 100644
--- a/libc/utils/cmake_format_test.py
+++ b/libc/utils/cmake_format_test.py
@@ -545,6 +545,61 @@ def test_stdout_write_keeps_lf_endings(self):
         )
         self.assertEqual(proc.stdout, expected)
 
+    def test_dry_run_
diff _outputs_pure_
diff (self):
+        """--dry-run --
diff  exits 1 and outputs only the unified 
diff ."""
+        import subprocess
+        import tempfile
+
+        code = "add_library(foo  STATIC\n  a.c\n)\n"
+
+        with tempfile.TemporaryDirectory() as tmpdir:
+            path = os.path.join(tmpdir, "CMakeLists.txt")
+            with open(path, "w", encoding="utf-8", newline="\n") as f:
+                f.write(code)
+
+            proc = subprocess.run(
+                [
+                    sys.executable,
+                    os.path.join(SCRIPT_DIR, "cmake_format.py"),
+                    "--dry-run",
+                    "--
diff ",
+                    path,
+                ],
+                stdout=subprocess.PIPE,
+                stderr=subprocess.PIPE,
+                text=True,
+            )
+            self.assertEqual(proc.returncode, 1)
+            self.assertTrue(proc.stdout.startswith("--- a/"))
+            self.assertNotIn("Formatting needed:", proc.stdout)
+            self.assertNotIn("file(s) need formatting.", proc.stdout)
+
+    def test_parse_error_exits_nonzero(self):
+        """A file with a CMake syntax error causes the CLI to exit with code 1."""
+        import subprocess
+        import tempfile
+
+        with tempfile.TemporaryDirectory() as tmpdir:
+            path = os.path.join(tmpdir, "CMakeLists.txt")
+            with open(path, "w", encoding="utf-8", newline="\n") as f:
+                f.write('set(FOO "unterminated)\n')
+
+            proc = subprocess.run(
+                [
+                    sys.executable,
+                    os.path.join(SCRIPT_DIR, "cmake_format.py"),
+                    "--dry-run",
+                    "--
diff ",
+                    path,
+                ],
+                stdout=subprocess.PIPE,
+                stderr=subprocess.PIPE,
+                text=True,
+            )
+            self.assertEqual(proc.returncode, 1)
+            self.assertEqual(proc.stdout, "")
+            self.assertIn("Error parsing file", proc.stderr)
+
 
 if __name__ == "__main__":
     unittest.main()

diff  --git a/llvm/utils/git/code-format-helper.py b/llvm/utils/git/code-format-helper.py
index 40d6709682d2cd..e7a82b8766d7f9 100755
--- a/llvm/utils/git/code-format-helper.py
+++ b/llvm/utils/git/code-format-helper.py
@@ -22,8 +22,8 @@
 check the coding style before submitting it. The canonical source of this script
 is in the LLVM source tree under llvm/utils/git.
 
-For C/C++ code it uses clang-format and for Python code it uses darker (which
-in turn invokes black).
+For C/C++ code it uses clang-format, for Python code it uses darker (which
+in turn invokes black), and for LLVM-libc CMake files it uses cmake_format.py.
 
 You can learn more about the LLVM coding style on llvm.org:
 https://llvm.org/docs/CodingStandards.html
@@ -33,8 +33,9 @@
 
 ln -s $(pwd)/llvm/utils/git/code-format-helper.py .git/hooks/pre-commit
 
-You can control the exact path to clang-format or darker with the following
-environment variables: $CLANG_FORMAT_PATH and $DARKER_FORMAT_PATH.
+You can control the exact path to clang-format, darker, or cmake_format.py with
+the following environment variables: $CLANG_FORMAT_PATH, $DARKER_FORMAT_PATH,
+and $CMAKE_FORMAT_PATH.
 """
 
 
@@ -466,7 +467,123 @@ def format_run(self, changed_files: List[str], args: FormatArgs) -> Optional[str
         return report
 
 
-ALL_FORMATTERS = (DarkerFormatHelper(), ClangFormatHelper(), UndefGetFormatHelper())
+class CMakeFormatHelper(FormatHelper):
+    name = "cmake-format"
+    friendly_name = "CMake code formatter"
+
+    def _construct_command(self) -> List[str]:
+        return [
+            sys.executable,
+            self.cmake_fmt_path,
+            "--dry-run",
+            "--
diff ",
+        ] + self._cmake_files
+
+    @property
+    def instructions(self) -> str:
+        return " ".join(["python3", self.cmake_fmt_path, "-i"] + self._cmake_files)
+
+    @property
+    def check_instructions(self) -> str:
+        return " ".join(
+            ["python3", self.cmake_fmt_path, "--dry-run", "--
diff "] + self._cmake_files
+        )
+
+    def pr_comment_text_for_
diff (self, 
diff : str) -> str:
+        return f"""
+:warning: {self.friendly_name}, {self.name} found issues in your code. :warning:
+
+<details>
+<summary>
+You can fix this locally with the following command:
+</summary>
+
+``````````bash
+{self.instructions}
+``````````
+
+You can also preview the formatting 
diff  without modifying files:
+
+``````````bash
+{self.check_instructions}
+``````````
+
+</details>
+
+<details>
+<summary>
+View the 
diff  from {self.name} here.
+</summary>
+
+``````````
diff 
+{
diff }
+``````````
+
+</details>
+"""
+
+    def filter_changed_files(self, changed_files: List[str]) -> List[str]:
+        filtered_files = []
+        for path in changed_files:
+            if not path.startswith("libc/"):
+                continue
+            if os.path.basename(path) == "CMakeLists.txt" or path.endswith(".cmake"):
+                if os.path.exists(path):
+                    filtered_files.append(path)
+        return filtered_files
+
+    @property
+    def cmake_fmt_path(self) -> str:
+        if "CMAKE_FORMAT_PATH" in os.environ:
+            return os.environ["CMAKE_FORMAT_PATH"]
+        return "libc/utils/cmake_format.py"
+
+    def has_tool(self) -> bool:
+        return os.path.isfile(self.cmake_fmt_path)
+
+    def format_run(self, changed_files: List[str], args: FormatArgs) -> Optional[str]:
+        cmake_files = self.filter_changed_files(changed_files)
+        if not cmake_files:
+            return None
+        self._cmake_files = cmake_files
+        cmake_cmd = self._construct_command()
+        if args.verbose:
+            print(f"Running: {' '.join(cmake_cmd)}")
+        proc = subprocess.run(cmake_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        if args.verbose:
+            sys.stdout.write(proc.stderr.decode("utf-8"))
+
+        if proc.returncode != 0:
+            # formatting needed, or the command otherwise failed
+            stdout = proc.stdout.decode("utf-8")
+            if args.verbose:
+                print(f"error: {self.name} exited with code {proc.returncode}")
+                if stdout:
+                    print(
+                        "error: CMake files are not formatted according to "
+                        "LLVM-libc style."
+                    )
+                    print(f"To fix this locally, run:\n  {self.instructions}")
+                    print(
+                        "To preview the formatting 
diff  locally, run:\n"
+                        f"  {self.check_instructions}"
+                    )
+                    # Print the 
diff  in the log so that it is viewable there
+                    print(stdout)
+            elif stdout:
+                print(f"To fix CMake formatting, run:\n  {self.instructions}")
+            return stdout
+        else:
+            sys.stdout.write(proc.stdout.decode("utf-8"))
+            return None
+
+
+ALL_FORMATTERS = (
+    DarkerFormatHelper(),
+    ClangFormatHelper(),
+    CMakeFormatHelper(),
+    UndefGetFormatHelper(),
+)
 
 
 def hook_main():


        


More information about the libc-commits mailing list