Using clang-format to Enforce Style

Everyone has their own coding style. Conforming to one particular style or another can be difficult, but with clang-format it doesn't have to be. Given a file (or collection of files), clang-format will modify it so that it meets certain style requirements. Several pre-configured styles already exist, such as llvm, Google, Chromium, Mozilla, and Webkit. For example, suppose we have the main.cpp file:

1
2
3
4
5
6
#include <iostream>

int main() {
std::cout << "Hello world\n";
return 0;
}

We can format the file according to Mozilla's styleguide with:

1
clang-format -i -style=Mozilla main.cpp

And end up with:

1
2
3
4
5
6
7
8
#include <iostream>

int
main()
{
  std::cout << "Hello world\n";
  return 0;
}

If you don't like any of the pre-configured styles, you can create a .clang-format file with your own rules. Simply replace Mozilla with file and clang-format will look for a .clang-format file in your current directory to use. Check out this amazing clang-format configurator to help define your own style.

Using clang-format with CMake

If you are using CMake to build your project, then it probably makes sense to have it handle clang-format for you. The first thing to do is to check if the clang-format executable exists:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
find_program(
  CLANG_FORMAT_EXE
  NAMES "clang-format"
  DOC "Path to clang-format executable"
  )
if(NOT CLANG_FORMAT_EXE)
  message(STATUS "clang-format not found.")
else()
  message(STATUS "clang-format found: ${CLANG_FORMAT_EXE}")
  set(DO_CLANG_FORMAT "${CLANG_FORMAT_EXE}" "-i -style=file")
endif()

Using DO_CLANG_FORMAT we can simply pass in the files that need to be formatted. Typically a CMake project will have a list with all the files that are part of a given target:

1
2
3
4
5
set(
  MY_PROJECT_SOURCE_FILES
  include/hello_world.hpp
  src/main.cpp
  )

Unfortunately passing these files straight to our DO_CLANG_FORMAT won't work because the path to the files is relative. We need to prefix each file with the full path in order to get it to work. Searching around stackoverflow I came across a handy prepend function to do just that. The first argument passed to the function will contain the result, the second argument is the prefix, and the last argument (not named in the function) is a list of files to be prefixed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
function(prepend var prefix)
  set(listVar "")

  foreach(f ${ARGN})
    list(APPEND listVar "${prefix}/${f}")
  endforeach()

  set(${var} "${listVar}" PARENT_SCOPE)
endfunction()

if(CLANG_FORMAT_EXE)
  prepend(FILES_TO_FORMAT ${CMAKE_CURRENT_SOURCE_DIR} ${MY_PROJECT_SOURCE_FILES})

  add_custom_target(
    clang-format-project-files
    COMMAND ${CLANG_FORMAT_EXE} -i -style=file ${FILES_TO_FORMAT}
  )
endif()

CMake will now generate a custom target that can be executed to format the files. If you use makefiles, it can be invoked easily with:

1
make clang-format-project-files

And there you have it - free formatting!