# Whats the idiomatic way to run clang-tidy on header files with CMake?

**URL:** https://discourse.cmake.org/t/whats-the-idiomatic-way-to-run-clang-tidy-on-header-files-with-cmake/9530
**Category:** Usage
**Tags:** comp:clang
**Created:** [November 30, 2023, 5:36pm UTC](https://discourse.cmake.org/t/whats-the-idiomatic-way-to-run-clang-tidy-on-header-files-with-cmake/9530 "2023-11-30T17:36:19Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![tom](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/t/3d9bf3/32.png) [@tom](https://discourse.cmake.org/u/tom)
#### Post date: [November 30, 2023, 5:36pm UTC](https://discourse.cmake.org/t/whats-the-idiomatic-way-to-run-clang-tidy-on-header-files-with-cmake/9530/1 "2023-11-30T17:36:19Z")

</div>

I would like to run clang-tidy on header files. I would also like to apply the fixits that are automatically generated. This is not trivial, because my header files are included many times throughout my codebase, so my fixits tend to get applied many times which leads to nonsense code (NULL → nullptrnullptr, and similar).

CMake seems to expect me to use` CMAKE_<LANG>_CLANG_TIDY` to point to the clang-tidy binary itself, and `CMAKE_<LANG>_CLANG_TIDY_EXPORT_FIXES_DIR` to dump the fixits to a set of yaml files. There doesn’t seem to be a wrapper for then applying those fixes, so I run clang-apply-replacements manually. Replacements in header files get applied many times.

LLVM seem to have a different solution. They supply a script called `run-clang-tidy`, which does three things:

1. Runs clang-tidy (using the compile\_commands.json file rather than running an entire build),
2. Collects all the yaml files into one enormous yaml file,
3. Calls clang-apply-replacements on the enormous yaml file, which seems to de-duplicate the fixes and apply them properly.

Unfortunately, the run-clang-tidy script _always_ runs clang-tidy - there is no “only apply fixes” option. It therefore doesn’t play very nicely with CMake’s implementation.

It seems like CMake and LLVM have different opinions about how best to run clang-tidy in these circumstances. Have I missed something?

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [November 30, 2023, 6:01pm UTC](https://discourse.cmake.org/t/whats-the-idiomatic-way-to-run-clang-tidy-on-header-files-with-cmake/9530/2 "2023-11-30T18:01:04Z")

</div>

> [@tom](#):
>
> Unfortunately, the run-clang-tidy script _always_ runs clang-tidy - there is no “only apply fixes” option. It therefore doesn’t play very nicely with CMake’s implementation.

This seems like a useful feature to request.

> [@tom](#):
>
> It seems like CMake and LLVM have different opinions about how best to run clang-tidy in these circumstances. Have I missed something?

`compile_commands.json` doesn’t really support a way to specify headers as they’re not compiled. CMake prefers to run `clang-tidy` with the compiler so that it is integrated into the build graph (e.g., a header might be generated and just running `clang-tidy` may fail if the header is not made up-to-date before running `clang-tidy`.

---

<div class="post-metadata">

### Author: ![tom](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/t/3d9bf3/32.png) [@tom](https://discourse.cmake.org/u/tom)
#### Post date: [November 30, 2023, 6:20pm UTC](https://discourse.cmake.org/t/whats-the-idiomatic-way-to-run-clang-tidy-on-header-files-with-cmake/9530/3 "2023-11-30T18:20:12Z")

</div>

> This seems like a useful feature to request.

Perhaps the first thing to do is to ask LLVM to look again at the scripting around clang-tidy. It seems like the obvious place for this de-duplication to take place is perhaps in clang-apply-replacements itself? Or maybe run-clang-tidy can be made more modular (there’s already a comment saying it should be merged with clang-tidy-diff.py…). Once we have the right tools on the LLVM end, integrating them into CMake becomes easier and both projects end up pulling in the same direction. I’ll raise something with LLVM tomorrow (unless you know an LLVM person on this forum you can tag?).

> `compile_commands.json` doesn’t really support a way to specify headers

For clarity, what I _think_ happens is that clang-tidy runs per Translation Unit. It’s able to relate different parts of the TU to source files. If you run clang-tidy on `foo.cpp`, clang-tidy can always “see” the code from the includes, and it decides whether to complain about it based on various HeaderFilter options.

Our build is very expensive, so being able to run clang-tidy without invoking the whole build is attractive.  
I’m sure I’ve seen a request for some sort of “null” build before, where instead of invoking the compiler CMake just touches files and runs custom targets… This might be a bit of a side-line. Let’s talk to the LLVM people first.

---

<div class="post-metadata">

### Author: ![tom](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/t/3d9bf3/32.png) [@tom](https://discourse.cmake.org/u/tom)
#### Post date: [December 1, 2023, 9:41am UTC](https://discourse.cmake.org/t/whats-the-idiomatic-way-to-run-clang-tidy-on-header-files-with-cmake/9530/4 "2023-12-01T09:41:05Z")

</div>

LLVM discourse topic [here](https://discourse.llvm.org/t/refactoring-run-clang-tidy-and-friends-for-better-cmake-integration/75372)

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [December 1, 2023, 11:40am UTC](https://discourse.cmake.org/t/whats-the-idiomatic-way-to-run-clang-tidy-on-header-files-with-cmake/9530/5 "2023-12-01T11:40:23Z")

</div>

> [@tom](#):
>
> LLVM discourse topic [here](https://discourse.llvm.org/t/refactoring-run-clang-tidy-and-friends-for-better-cmake-integration/75372)

Thanks; I’ve subscribed myself.

> [@tom](#):
>
> Our build is very expensive, so being able to run clang-tidy without invoking the whole build is attractive.  
> I’m sure I’ve seen a request for some sort of “null” build before, where instead of invoking the compiler CMake just touches files and runs custom targets…

That causes consistency problems because if you build after doing a “null” build, you end up with all kinds of missing symbols because the libraries are “nothing”. There have been thoughts of support along these lines, but it’s not clear when they’ll be done (ideally 2024).

---

<div class="post-metadata">

### Author: ![Ryanf55](https://discourse.cmake.org/user_avatar/discourse.cmake.org/ryanf55/32/3516_2.png) [@Ryanf55](https://discourse.cmake.org/u/Ryanf55)
#### Post date: [January 30, 2024, 4:34am UTC](https://discourse.cmake.org/t/whats-the-idiomatic-way-to-run-clang-tidy-on-header-files-with-cmake/9530/6 "2024-01-30T04:34:13Z")

</div>

Is there a workaround? Even the supposed workflow to run clang-tidy manually on sources given a compilation database and supply the path to a single header do not seem to work.

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [February 4, 2024, 1:29pm UTC](https://discourse.cmake.org/t/whats-the-idiomatic-way-to-run-clang-tidy-on-header-files-with-cmake/9530/7 "2024-02-04T13:29:43Z")

</div>

Have you tried the `--header-filter=` option?

---

<div class="post-metadata">

### Author: ![Ryanf55](https://discourse.cmake.org/user_avatar/discourse.cmake.org/ryanf55/32/3516_2.png) [@Ryanf55](https://discourse.cmake.org/u/Ryanf55)
#### Post date: [February 4, 2024, 5:24pm UTC](https://discourse.cmake.org/t/whats-the-idiomatic-way-to-run-clang-tidy-on-header-files-with-cmake/9530/8 "2024-02-04T17:24:49Z")

</div>

No, I’ll give it a try and report back. Thanks for the tip!
