Skip to content

c formatting

Graham Lopez edited this page Jun 20, 2019 · 1 revision

This page gives some hints about installing clang-format and how to use it on its own, integrated with vim/emacs, or with git.

Remember, clang-format can be selectively disabled for certain chunks of code (e.g. nicely formatted matrix literals, etc.) with

// clang-format off
Matrix my_matrix = { {1, 2, 3},
                     {4, 5, 6},
                     {7, 8 ,9} };
// clang-format on

Of course, this should be used as sparingly as possible.

install clang format

Mac OSX

clang-format is available on Mac OSX in both macports and homebrew.

Ubuntu

using apt

Configure apt to pull directly from apt.llvm.org's package index:

Add the archive signature (same signature for all versions):

$ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -

For example, for llvm 7.0 on Ubuntu 18.04

$ echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main" >
/etc/apt/sources.list.d/llvm.list
$ echo "deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main" >
/etc/apt/sources.list.d/llvm.list

Now install using apt:

$ apt update
$ apt install clang-format-7

download pre-built binaries

Install the pre-build binaries on almost any ubuntu-based distro:

wget http://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
tar xvJf ./clang+llvm-7.0.0*
cp clang+llvm-7.0.0*/bin/clang-format </somewhere/in/your/PATH>

use clang-format with git

using git hooks

This is likely the easiest and safest way to use clang-format if you aren't using it within your editor as you are writing the code itself.

This pre-commit hook will run any time git commit is executed. It will check the files to be committed, and if there are formatting errors, it will show the diff, and ask the user if they wish to format them or abort.

Be sure to check the diff and ensure that the formatting is what you want.

Add the following to local_git_repo/.git/hooks/pre-commit

#!/bin/bash

# git pre-commit hook that checks the to-be-committed files, and offers to
# format them if necesssary
#
# M. Graham Lopez (2018)

echo "pre-commit hook checking code formatting"

clean=0
# the list of files to be committed
for bob in $(git diff --cached --name-status | awk '$1 != "D" { print $2 }' | grep '\.cpp$\|\.hpp$'); do
  diff -u --color ${bob} <(clang-format ${bob})
  if [[ $? != 0 ]] ; then clean=1 ; fi # save if we saw a difference
done

if [[ $clean == 1 ]] ; then
  echo ""
  echo "There are un-formatted changes being commited"
  echo "Choose to (C)ommit anyway, (F)ormat all and commit, (A)bort the commit"
  exec < /dev/tty
  PS3="Select: "
  select yn in "Commit" "Format" "Abort"; do
    casevar=${yn:-$REPLY}
    case $casevar in
      1|Commit|C|c)
        echo "okay, continuing with commit anyway"
        exit 0
        break
        ;;
      2|Format|F|f)
        echo "formatting"
        for bob in $(git diff --cached --name-status | awk '$1 != "D" { print $2 }') ; do
          clang-format -i ${bob}
          git add ${bob}
        done
        exit 0
        ;;
      3|Abort|A|a)
        echo "exiting"
        exit 1
        ;;
    esac
  done
else # there were no differences
  exit 0
fi

manual / supervised

Add the git integration file somewhere in your path

The workflow to format your changed code:

  • Make codes changes in your working copy.
  • Run git add your_changed_file.cpp
  • Run git clang-format --extensions cpp,hpp, and you will probably see modifications in your_changed_file.cpp, these modifications are generated from clang-format.
  • Run git add your_changed_file.cpp, and commit your change. Now the branch is ready to be opened as a pull request.

If you want to format the changed code on your latest git commit (HEAD), you can run git clang-format --extensions cpp,hpp HEAD~1. See git clang-format -h for more details.

using clang-format standalone

  • clang-format <file(s)> will print to stdout the formatted file(s)
  • clang-format -i <file(s)> will format (edit) the file(s) in place
  • diff -u --color file.cpp <(clang-format file.cpp) to see the potential changes (may not work in a script)
  • clang-format file.cpp | diff file.cpp - (alternate) to see the potential changes

to only check and report if a failure over a group of files, e.g. within a CI script:

  • for bob in $(ls src/*) ; do diff ${bob} <(clang-format ${bob}) || exit ; done

use clang-format within Vim

configure Vim for use with clang-format

  • find the clang-format.py that came with your clang-format installtion. In the LLVM install tree, it is at share/clang/clang-format.py or grab the latest one here. It is not version dependent.
  • add this file to your path. It allows vim to interface with whichever clang-format shows up first in the user's path.

for on-demand formatting (preferred)

The following in your .vimrc will cause "ctrl+f" to apply the clang-format style to the current line in normal or insert mode, or a visual selection (use shift+v + movement in normal mode to make selection):

 if has('python3')
   noremap <C-f> :py3f /usr/local/bin/clang-format.py<cr>
   inoremap <C-f> :py3f /usr/local/bin/clang-format.py<cr>
 endif

automatically on file save

This will make changes without the ability to verify them first. use caution

Add something like the following to your .vimrc:

function! Formatonsave()
  let l:formatdiff = 1
  pyf ~/llvm/tools/clang/tools/clang-format/clang-format.py
endfunction
autocmd BufWritePre *.h,*.cc,*.cpp call Formatonsave()

configure Emacs for use with clang-format

(Under Construction)

This file, and the instructions at the top of it are a good place to start: https://github.com/llvm-mirror/clang/blob/master/tools/clang-format/clang-format.el

add this to your .emacs

(load "<path-to-clang>/tools/clang-format/clang-format.el")
(global-set-key [C-M-tab] 'clang-format-region)