Is there a way to call something like clang-format --style=Webkit
for an entire cpp project folder, rather than running it separately for each file?
I am using clang-format.py
and vim
to do this, but I assume there is a way to apply this once.
Unfortunately, there is no way to apply clang-format recursively. *.cpp
will only match files in the current directory, not subdirectories. Even **/*
doesn't work.
Luckily, there is a solution: grab all the file names with the find
command and pipe them in. For example, if you want to format all .h
and .cpp
files in the directory foo/bar/
recursively, you can do
find foo/bar/ -iname *.h -o -iname *.cpp | xargs clang-format -i
See here for additional discussion.
First create a .clang-format
file if it doesn't exist:
clang-format -style=WebKit -dump-config > .clang-format
Choose whichever predefined style you like, or edit the resulting .clang-format
file.
clang-format configurator is helpful.
Then run:
find . -regex '.*\.\(cpp\|hpp\|cc\|cxx\)' -exec clang-format -style=file -i {} \;
Other file extensions than cpp
, hpp
, cc
and cxx
can be used in the regular expression, just make sure to separate them with \|
.
I recently found a bash-script which does exactly what you need:
https://github.com/eklitzke/clang-format-all
This is a bash script that will run
clang-format -i
on your code.Features:
- Finds the right path to
clang-format
on Ubuntu/Debian, which encode the LLVM version in theclang-format
filename- Fixes files recursively
- Detects the most common file extensions used by C/C++ projects
On Windows, I used it successfully in Git Bash and WSL.
For the Windows users: If you have Powershell 3.0 support, you can do:
Get-ChildItem -Path . -Directory -Recurse |
foreach {
cd $_.FullName
&clang-format -i -style=WebKit *.cpp
}
Note1: Use pushd .
and popd
if you want to have the same current directory before and after the script
Note2: The script operates in the current working directory
Note3: This can probably be written in a single line if that was really important to you
The below script and process:
clang-format
downloaded and installed.Here's how I do it:
I create a run_clang_format.sh
script and place it in the root of my project directory, then I run it from anywhere. Here's what it looks like:
run_clang_format.sh
#!/bin/bash
THIS_PATH="$(realpath "$0")"
THIS_DIR="$(dirname "$THIS_PATH")"
# Find all files in THIS_DIR which end in .ino, .cpp, etc., as specified
# in the regular expression just below
FILE_LIST="$(find "$THIS_DIR" | grep -E ".*(\.ino|\.cpp|\.c|\.h|\.hpp|\.hh)$")"
echo -e "Files found to format = \n\"\"\"\n$FILE_LIST\n\"\"\""
# Format each file.
# - NB: do NOT put quotes around `$FILE_LIST` below or else the `clang-format` command will
# mistakenly see the entire blob of newline-separated file names as a SINGLE file name instead
# of as a new-line separated list of *many* file names!
clang-format --verbose -i --style=file $FILE_LIST
Using --style=file
means that I must also have a custom .clang-format
clang-format specifier file at this same level, which I do.
Now, make your newly-created run_clang_format.sh
file executable:
chmod +x run_clang_format.sh
...and run it:
./run_clang_format.sh
Here's a sample run and output for me:
~/GS/dev/eRCaGuy_PPM_Writer$ ./run_clang-format.sh
Files found to format =
"""
/home/gabriel/GS/dev/eRCaGuy_PPM_Writer/examples/PPM_Writer_demo/PPM_Writer_demo.ino
/home/gabriel/GS/dev/eRCaGuy_PPM_Writer/examples/PPM_Writer_demo2/PPM_Writer_demo2.ino
/home/gabriel/GS/dev/eRCaGuy_PPM_Writer/src/eRCaGuy_PPM_Writer.h
/home/gabriel/GS/dev/eRCaGuy_PPM_Writer/src/eRCaGuy_PPM_Writer.cpp
/home/gabriel/GS/dev/eRCaGuy_PPM_Writer/src/timers/eRCaGuy_TimerCounterTimers.h
"""
Formatting /home/gabriel/GS/dev/eRCaGuy_PPM_Writer/examples/PPM_Writer_demo/PPM_Writer_demo.ino
Formatting /home/gabriel/GS/dev/eRCaGuy_PPM_Writer/examples/PPM_Writer_demo2/PPM_Writer_demo2.ino
Formatting /home/gabriel/GS/dev/eRCaGuy_PPM_Writer/src/eRCaGuy_PPM_Writer.h
Formatting /home/gabriel/GS/dev/eRCaGuy_PPM_Writer/src/eRCaGuy_PPM_Writer.cpp
Formatting /home/gabriel/GS/dev/eRCaGuy_PPM_Writer/src/timers/eRCaGuy_TimerCounterTimers.h
You can find my run_clang_format.sh
file in my eRCaGuy_PPM_Writer repository, and in my eRCaGuy_CodeFormatter repository too.
clang-format
in my "git & Linux cmds, help, tips & tricks - Gabriel.txt" doc in my eRCaGuy_dotfiles repo (search the document for "clang-format").clang-format
documentation, setup, instructions, etc! https://clang.llvm.org/docs/ClangFormat.htmlclang-format
auto-formatter/linter executable for Windows, or other installers/executables here: https://llvm.org/builds/I'm using the following command to format all objective-C files under the current folder recursively:
$ find . -name "*.m" -o -name "*.h" | sed 's| |\\ |g' | xargs clang-format -i
I've defined the following alias in my .bash_profile
to make things easier:
# Format objC files (*.h and *.m) under the current folder, recursively
alias clang-format-all="find . -name \"*.m\" -o -name \"*.h\" | sed 's| |\\ |g' | xargs clang-format -i"
Here is a solution that searches recursively and pipes all files to clang-format as a file list in one command. It also excludes the "build" directory (I use CMake), but you can just omit the "grep" step to remove that.
shopt -s globstar extglob failglob && ls **/*.@(h|hpp|hxx|c|cpp|cxx) | grep -v build | tr '\n' ' ' | xargs clang-format -i