Clang-tidy on windows
As I am
not that proficient in PowerShell
prefer to reuse as much as possible existing solutions
have a bash shell on Windows thanks to Cygwin
I decided to use clang-tidy from Cygwin. Unfortunately, it is not packaged for it.
But Cygwin provides the necessary tools for interacting with "native" windows executables, and as it turns out, it can be done easily.
First, download and install the LLVM suite on Windows. If you can, use the 64 bit executable, and I would not recommend adding the tools to the path.
The python script
run-clang-tidy.py is missing, this can be downloaded from github.
In my current configuration, I have the official python3 port for windows, and not the python version packaged for Cygwin (as I like to avoid having duplicate programs).
Now that we have all the tools, it’s time to see how to put them together.
From Cygwin prompt, let’s check what checks are available:
'C:/Program Files/LLVM/bin/clang-tidy.exe' --list-checks -checks='*'
As a first test, lets' use
run-clang-tidy.py is flexible and can, fortunately, accept toolchains outside of
PATH. As I’m using the Windows version of python (the non-Cygwin version), I need to use Windows paths:
python3 "<path to run-clang-tidy.py>" -clang-apply-replacements 'C:/Program Files/LLVM/bin/clang-apply-replacements.exe' -clang-tidy-binary 'C:/Program Files/LLVM/bin/clang-tidy.exe' -header-filter='.*' -checks='-*,modernize-use-nullptr' -p <dir-containing-compile_commands.json> -fix
Note: on a GNU/Linux distribution, with all tools installed from the package manager, the command would look like
run-clang-tidy -header-filter='.*' -checks='-*,modernize-use-nullptr' -p <dir-containing-compile_commands.json> -fix
To make things less cumbersome, it is possible to add a script similar to the following in your
run-clang-tidyin your Cygwin
#!/bin/sh clang_bin_dir='C:/Program Files/LLVM/bin' clang_apply_replacements="$clang_bin_dir/clang-apply-replacements.exe"; clang_tidy_binary="$clang_bin_dir/clang-tidy.exe"; python3 "<path to run-clang-tidy.py>" -clang-apply-replacements "$clang_apply_replacements" -clang-tidy-binary "$clang_tidy_binary" "$@";
Note that edits are made at the end, thus better not touch any file in the meantime.
Unfortunately, this process can take a lot of time on bigger projects, unless you have multiple copies of your code, you might want to take a break. Thus I prefer to save the result on an external file:
cd <directory where compile_commands.json is located> python3 "<path to run-clang-tidy.py>" -clang-apply-replacements 'C:/Program Files/LLVM/bin/clang-apply-replacements.exe' -clang-tidy-binary 'C:/Program Files/LLVM/bin/clang-tidy.exe' -header-filter='.*' -checks='-*,modernize-use-nullptr' -export-fixes ./modernize-use-nullptr.yml # or, thanks to the script run-clang-tidy -header-filter='.*' -checks='-*,modernize-use-nullptr' -export-fixes ./modernize-use-nullptr.yml
Notice that in this case, you might need to install the optional dependency
It can be installed through
pip from an admin PowerShell console (admin rights are not required, but in that case, you might need to adjust some paths)
& 'C:\Program Files\Python38\python.exe' -m pip install pyyaml
Again, the output is written at the end of the process. But at least it is possible to
continue working/editing our source files, at worst some proposed fix will not apply cleanly
review the changes before applying them
Of course, it is possible to execute more than just one type of analysis:
cd <directory where compile_commands.json is located> run-clang-tidy -header-filter='.*' -checks='-*,modernize*' -export-fixes ./modernize.yml
How to skip folders or restrict changes to a given folder?
clang-tidy uses as input
compile_command.json. This means that by editing it, it is possible to exclude files, for example, we do not want to spend time analyzing files we cannot change, like the dependencies of our project.
Taking advantage of a revision control system, and undoing changes to files we do not want to edit is suboptimal as we are still spending time analyzing those files. For a bigger project with many dependencies, this could be a lot of time.
compile_command.json file by hand is a tedious and error-prone task, fortunately, we can use jq (already packaged in Cygwin), for this task.
Supposing that our external dependencies are all located in an
extern folder, we can filter those
.json entries out:
jq -c '[. | select(.file | contains("extern") | not)]'
clang-tidy currently accepts only
compile_command.json as a compilation database name. So either save a copy somewhere else or overwrite the file.
cat compile_command.json | jq -c '[. | select(.file | contains("extern") | not)]' > /tmp/compile_command.json # or cat compile_command.json | jq -c '[. | select(.file | contains("extern") | not)]' | sponge compile_command.json
If we want to analyze only a specific folder, for example, we want only to apply changes to a library located in the folder
cat compile_command.json | jq -c '[. | select(.file | contains("libfoo"))]' > /tmp/compile_command.json
Cppcheck can use the
compile_command.json database to, so being able to edit it efficiently is a must when using both analyzers.
I’ve decided that I wanted to use clang-tidy from the command line because it makes it trivial to automate tasks. Nevertheless, integrating it with the IDE has the advantage that it can make some interactive tasks easier. Nevertheless, I prefer to run the analysis from the command line, as it is generally an intensive task, and in the meantime, I would like to use the IDE for something else.
The great thing about QtCreator (I do not know about other IDE), is that it makes it possible to import the
.yml file generated with
QtCreator also has another advantage; it makes it possible to create a
compile_command.json file, (at least for CMake projects), even for Visual Studio Solutions. Normally you can create it directly with
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON, which is ignored when creating a visual studio solution), or with other programs.
Do you want to share your opinion? Or is there an error, same parts that are not clear enough?
You can contact me here.