How to call clang-format over a cpp project folder?

C++ClangClang Format

C++ Problem Overview


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.

C++ Solutions


Solution 1 - C++

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.

Solution 2 - C++

What about:

clang-format -i -style=WebKit *.cpp *.h

in the project folder. The -i option makes it inplace (by default formatted output is written to stdout).

Solution 3 - C++

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

Solution 4 - C++

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 the clang-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.

Solution 5 - C++

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

Solution 6 - C++

When you use Windows (CMD) but don't want to use the PowerShell cannon to shoot this fly, try this:

for /r %t in (*.cpp *.h) do clang-format -i -style=WebKit "%t"

Don't forget to duplicate the two %s if in a cmd script.

Solution 7 - C++

The below script and process:

  1. works in Linux
  2. should work on MacOS
  3. works in Windows inside Git For Windows terminal with 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. My .clang-format file is there too.

References:

  1. My repository:
    1. eRCaGuy_PPM_Writer repo
    2. run_clang_format.sh file
  2. My notes on how to use clang-format in my "git & Linux cmds, help, tips & tricks - Gabriel.txt" doc in my eRCaGuy_dotfiles repo (search the document for "clang-format").
  3. Official clang-format documentation, setup, instructions, etc! https://clang.llvm.org/docs/ClangFormat.html
  4. Download the clang-format auto-formatter/linter executable for Windows, or other installers/executables here: https://llvm.org/builds/
  5. Clang-Format Style Options: https://clang.llvm.org/docs/ClangFormatStyleOptions.html
  6. [my answer] https://stackoverflow.com/questions/59895/how-to-get-the-source-directory-of-a-bash-script-from-within-the-script-itself/60157372#60157372
  1. [my answer] https://stackoverflow.com/questions/24476165/indenting-preprocessor-directives-with-clang-format/66004745#66004745

See also:

  1. [my answer] https://stackoverflow.com/questions/67678531/fixing-a-simple-c-code-without-the-coments/67678570#67678570

Solution 8 - C++

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"

Solution 9 - C++

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

Solution 10 - C++

In modern bash you can recursively crawl the file tree

for file_name in ./src/**/*.{cpp,h,hpp}; do
    if [ -f "$file_name" ]; then
        printf '%s\n' "$file_name"
        clang-format -i $file_name
    fi
done

Here the source is assumed to be located in ./src and the .clang-format contains the formatting information.

Solution 11 - C++

As @sbarzowski touches on in a comment above, in bash you can enable globstar which causes ** to expand recursively.

If you just want it for this one command you can do something like the following to format all .h, .cc and .cpp files.

(shopt -s globstar; clang-format -i **/*.{h,cc,cpp})

Or you can add shopt -s globstar to your .bashrc and have ** goodness all the time in bash.

As a side note, you may want to use --dry-run with clang-format the first time to be sure it's what you want.

Solution 12 - C++

You can use this inside a Make file. It uses git ls-files --exclude-standard to get the list of the files, so that means untracked files are automatically skipped. It assumes that you have a .clang-tidy file at your project root.

format:
ifeq ($(OS), Windows_NT)
	pwsh -c '$$files=(git ls-files --exclude-standard); foreach ($$file in $$files) { if ((get-item $$file).Extension -in ".cpp", ".hpp", ".c", ".cc", ".cxx", ".hxx", ".ixx") { clang-format -i -style=file $$file } }'
else
	git ls-files --exclude-standard | grep -E '\.(cpp|hpp|c|cc|cxx|hxx|ixx)$$' | xargs clang-format -i -style=file
endif

Run with make format

Notice that I escaped $ using $$ for make.

If you use go-task instead of make, you will need this:

  format:
    - |
      {{if eq OS "windows"}} 
        powershell -c '$files=(git ls-files --exclude-standard); foreach ($file in $files) { if ((get-item $file).Extension -in ".cpp", ".hpp", ".c", ".cc", ".cxx", ".hxx", ".ixx") { clang-format -i -style=file $file } }' 
      {{else}} 
        git ls-files --exclude-standard | grep -E '\.(cpp|hpp|c|cc|cxx|hxx|ixx)$' | xargs clang-format -i -style=file 
      {{end}}

Run with task format

If you want to run the individual scripts, then use these

# powershell
$files=(git ls-files --exclude-standard); foreach ($file in $files) { if ((get-item $file).Extension -in ".cpp", ".hpp", ".c", ".cc", ".cxx", ".hxx", ".ixx") { clang-format -i -style=file $file } }
# bash
git ls-files --exclude-standard | grep -E '\.(cpp|hpp|c|cc|cxx|hxx|ixx)$' | xargs clang-format -i -style=file

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser3639557View Question on Stackoverflow
Solution 1 - C++AntimonyView Answer on Stackoverflow
Solution 2 - C++sbarzowskiView Answer on Stackoverflow
Solution 3 - C++AlexanderView Answer on Stackoverflow
Solution 4 - C++Julius BullingerView Answer on Stackoverflow
Solution 5 - C++Tim MeyerView Answer on Stackoverflow
Solution 6 - C++Michel de RuiterView Answer on Stackoverflow
Solution 7 - C++Gabriel StaplesView Answer on Stackoverflow
Solution 8 - C++marcelosalloumView Answer on Stackoverflow
Solution 9 - C++BimView Answer on Stackoverflow
Solution 10 - C++MikhailView Answer on Stackoverflow
Solution 11 - C++studgeekView Answer on Stackoverflow
Solution 12 - C++AminView Answer on Stackoverflow