mirror of
https://github.com/ttroy50/cmake-examples.git
synced 2025-12-19 04:34:36 +03:00
add ability to check clang-format
This commit is contained in:
61
04-static-analysis/clang-format/.clang-format
Normal file
61
04-static-analysis/clang-format/.clang-format
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
# BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignEscapedNewlinesLeft: false
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: false
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Allman
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
ColumnLimit: 120
|
||||||
|
CommentPragmas: ''
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 8
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
MaxEmptyLinesToKeep: 3
|
||||||
|
NamespaceIndentation: All
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
PointerAlignment: Left
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp11
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
...
|
||||||
14
04-static-analysis/clang-format/CMakeLists.txt
Normal file
14
04-static-analysis/clang-format/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
cmake_minimum_required (VERSION 3.0)
|
||||||
|
|
||||||
|
project(cppcheck_analysis)
|
||||||
|
|
||||||
|
# Add a custom CMake Modules directory
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules
|
||||||
|
${CMAKE_MODULE_PATH})
|
||||||
|
|
||||||
|
# Add sub directories
|
||||||
|
add_subdirectory(subproject1)
|
||||||
|
add_subdirectory(subproject2)
|
||||||
|
|
||||||
|
set(CLANG_FORMAT_BIN_NAME clang-format-3.6)
|
||||||
|
find_package(ClangFormat)
|
||||||
142
04-static-analysis/clang-format/README.adoc
Normal file
142
04-static-analysis/clang-format/README.adoc
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
= clang-format
|
||||||
|
:toc:
|
||||||
|
:toc-placement!:
|
||||||
|
|
||||||
|
toc::[]
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
This example shows how to call the
|
||||||
|
https://clang.llvm.org/docs/ClangFormat.html[Clang Format] to check if your source code
|
||||||
|
matches against your code style guidelines.
|
||||||
|
|
||||||
|
The files included in this example are:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ tree
|
||||||
|
.
|
||||||
|
├── .clang-format
|
||||||
|
├── CMakeLists.txt
|
||||||
|
├── cmake
|
||||||
|
│ ├── modules
|
||||||
|
│ │ ├── clang-format.cmake
|
||||||
|
│ │ └── FindClangFormat.cmake
|
||||||
|
│ └── scripts
|
||||||
|
│ └── clang-format-check-changed
|
||||||
|
├── subproject1
|
||||||
|
│ ├── CMakeLists.txt
|
||||||
|
│ └── main1.cpp
|
||||||
|
└── subproject2
|
||||||
|
├── CMakeLists.txt
|
||||||
|
└── main2.cpp
|
||||||
|
```
|
||||||
|
|
||||||
|
* link:CMakeLists.txt[] - Top level CMakeLists.txt
|
||||||
|
* link:.clang-format - The file describing the stype guide
|
||||||
|
* link:cmake/modules/FindClangFormat.cmake - Script to find the clang-format binary
|
||||||
|
* link:cmake/modules/clang-format.cmake - Script to setup the format targets
|
||||||
|
* link:cmake/scripts/clang-format-check-changed - A helper script to check against changed files in git
|
||||||
|
* link:subproject1/CMakeLists.txt[] - CMake commands for subproject 1
|
||||||
|
* link:subproject1/main.cpp[] - source for a subproject with no errors
|
||||||
|
* link:subproject2/CMakeLists.txt[] - CMake commands for subproject 2
|
||||||
|
* link:subproject2/main2.cpp[] - source for a subproject that includes errors
|
||||||
|
|
||||||
|
# Requirements
|
||||||
|
|
||||||
|
To run this example you must have clang format tool installed. This can be installed on Ubuntu using the following command.
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
$ sudo apt-get install clang-format
|
||||||
|
----
|
||||||
|
|
||||||
|
It will result in the tool being available as:
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
$ clang-format
|
||||||
|
----
|
||||||
|
|
||||||
|
# Concepts
|
||||||
|
|
||||||
|
## clang-format
|
||||||
|
|
||||||
|
+clang-format+ can scan a source file then find and optionally format it to match your
|
||||||
|
companys style guidelines. There are default styles build in but you can also setup a style guide using a custom file called +.clang-format+, for example a snipped from this
|
||||||
|
repositories +.clang-format+ is below:
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
Language: Cpp
|
||||||
|
# BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
----
|
||||||
|
|
||||||
|
By default this will run the standard compiler for your platform, i.e. `gcc` on linux. However, if you want to override this you can change the command to:
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
$ scan-build-3.6 --use-cc=clang-3.6 --use-c++=clang++-3.6 -o ./scanbuildout/ make
|
||||||
|
----
|
||||||
|
|
||||||
|
## format style
|
||||||
|
|
||||||
|
As mentioned, the style in this example is based on the +.clang-format+ file. This can be changed by editing link:cmake/modules/clang-format.cmake[clang-format.cmake] and changing
|
||||||
|
the `-style=file` to the required style;
|
||||||
|
|
||||||
|
# Targets
|
||||||
|
|
||||||
|
This example will setup 3 targets:
|
||||||
|
|
||||||
|
* format
|
||||||
|
* format-check
|
||||||
|
* format-check-changed
|
||||||
|
|
||||||
|
## format
|
||||||
|
|
||||||
|
The format target will find any C++ source files and in place modify them to match the
|
||||||
|
+.clang-format+ style. The source files are found using the following cmake code
|
||||||
|
|
||||||
|
[source,cmake]
|
||||||
|
----
|
||||||
|
file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.h *.cxx *.hxx *.hpp *.cc)
|
||||||
|
|
||||||
|
# Don't include some common build folders
|
||||||
|
set(CLANG_FORMAT_EXCLUDE_PATTERNS ${CLANG_FORMAT_EXCLUDE_PATTERNS} "build/" "/CMakeFiles/")
|
||||||
|
|
||||||
|
# get all project files file
|
||||||
|
foreach (SOURCE_FILE ${ALL_SOURCE_FILES})
|
||||||
|
foreach (EXCLUDE_PATTERN ${CLANG_FORMAT_EXCLUDE_PATTERNS})
|
||||||
|
string(FIND ${SOURCE_FILE} ${EXCLUDE_PATTERN} EXCLUDE_FOUND)
|
||||||
|
if (NOT ${EXCLUDE_FOUND} EQUAL -1)
|
||||||
|
list(REMOVE_ITEM ALL_SOURCE_FILES ${SOURCE_FILE})
|
||||||
|
endif ()
|
||||||
|
endforeach ()
|
||||||
|
endforeach ()
|
||||||
|
----
|
||||||
|
|
||||||
|
This will find files matching the common C++ suffixes and then remove any that match some
|
||||||
|
common CMake build directories.
|
||||||
|
|
||||||
|
## format-check
|
||||||
|
|
||||||
|
This target will work as above but instead of formatting the files it will cause a failure
|
||||||
|
if any files don't match the clang-format style
|
||||||
|
|
||||||
|
## format-check-changed
|
||||||
|
|
||||||
|
This target will check the output of `git status` and scan the files to check if they match the style. This can be used by developers to make sure their changed files match the correct style.
|
||||||
|
|
||||||
|
In this example the actual check is done with a helper script +clang-format-check-changed+. This calls the following command to check files:
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
git status --porcelain \
|
||||||
|
| egrep '*\.cpp|*\.h|*\.cxx|*\.hxx|*\.hpp|*\.cc' \
|
||||||
|
| awk -F " " '{print $NF}' \
|
||||||
|
| xargs -r clang-format -style=file -output-replacements-xml \
|
||||||
|
| grep "replacement offset" 2>&1 > /dev/null
|
||||||
|
----
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Find Clang format
|
||||||
|
#
|
||||||
|
#
|
||||||
|
if(NOT CLANG_FORMAT_BIN_NAME)
|
||||||
|
set(CLANG_FORMAT_BIN_NAME clang-format)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# if custom path check there first
|
||||||
|
if(CPPCHECK_ROOT_DIR)
|
||||||
|
find_program(CLANG_FORMAT_BIN
|
||||||
|
NAMES
|
||||||
|
${CLANG_FORMAT_BIN_NAME}
|
||||||
|
PATHS
|
||||||
|
"${CLANG_FORMAT_ROOT_DIR}"
|
||||||
|
NO_DEFAULT_PATH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_program(CLANG_FORMAT_BIN NAMES ${CLANG_FORMAT_BIN_NAME})
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(
|
||||||
|
CLANG_FORMAT
|
||||||
|
DEFAULT_MSG
|
||||||
|
CLANG_FORMAT_BIN)
|
||||||
|
|
||||||
|
mark_as_advanced(
|
||||||
|
CLANG_FORMAT_BIN)
|
||||||
|
|
||||||
|
if(CLANG_FORMAT_FOUND)
|
||||||
|
# A CMake script to find all source files and setup clang-format targets for them
|
||||||
|
include(clang-format)
|
||||||
|
else()
|
||||||
|
message("clang-format not found. Not setting up format targets")
|
||||||
|
endif()
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# A CMake script to find all source files and setup clang-format targets for them
|
||||||
|
|
||||||
|
# Find all source files
|
||||||
|
file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.h *.cxx *.hxx *.hpp *.cc)
|
||||||
|
|
||||||
|
# Don't include some common build folders
|
||||||
|
set(CLANG_FORMAT_EXCLUDE_PATTERNS ${CLANG_FORMAT_EXCLUDE_PATTERNS} "main2.cpp" "build/" "/CMakeFiles/")
|
||||||
|
|
||||||
|
# get all project files file
|
||||||
|
foreach (SOURCE_FILE ${ALL_SOURCE_FILES})
|
||||||
|
foreach (EXCLUDE_PATTERN ${CLANG_FORMAT_EXCLUDE_PATTERNS})
|
||||||
|
string(FIND ${SOURCE_FILE} ${EXCLUDE_PATTERN} EXCLUDE_FOUND)
|
||||||
|
if (NOT ${EXCLUDE_FOUND} EQUAL -1)
|
||||||
|
list(REMOVE_ITEM ALL_SOURCE_FILES ${SOURCE_FILE})
|
||||||
|
endif ()
|
||||||
|
endforeach ()
|
||||||
|
endforeach ()
|
||||||
|
|
||||||
|
add_custom_target(format
|
||||||
|
COMMENT "Running clang-format to change files"
|
||||||
|
COMMAND ${CLANG_FORMAT_BIN}
|
||||||
|
-style=file
|
||||||
|
-i
|
||||||
|
${ALL_SOURCE_FILES}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(format-check
|
||||||
|
COMMENT "Checking clang-format changes"
|
||||||
|
COMMAND ${CLANG_FORMAT_BIN}
|
||||||
|
-style=file
|
||||||
|
-output-replacements-xml
|
||||||
|
${ALL_SOURCE_FILES}
|
||||||
|
| grep "replacement offset" 2>&1 > /dev/null
|
||||||
|
)
|
||||||
|
|
||||||
|
# This is a hack because our CMake root dir isn't the same as our git root dir
|
||||||
|
|
||||||
|
# Get the path to this file
|
||||||
|
get_filename_component(_clangcheckpath ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||||
|
# call the script to chech changed files in git
|
||||||
|
add_custom_target(format-check-changed
|
||||||
|
COMMENT "Checking changed files in git"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
COMMAND ${_clangcheckpath}/../scripts/clang-format-check-changed ${CLANG_FORMAT_BIN}
|
||||||
|
)
|
||||||
|
|
||||||
18
04-static-analysis/clang-format/cmake/scripts/clang-format-check-changed
Executable file
18
04-static-analysis/clang-format/cmake/scripts/clang-format-check-changed
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Required because cmake root isn't git root in this example
|
||||||
|
CLANG_FORMAT_BIN=$1
|
||||||
|
GIT_ROOT=`git rev-parse --show-toplevel`
|
||||||
|
|
||||||
|
pushd ${GIT_ROOT} > /dev/null
|
||||||
|
|
||||||
|
git status --porcelain \
|
||||||
|
| egrep '*\.cpp|*\.h|*\.cxx|*\.hxx|*\.hpp|*\.cc' \
|
||||||
|
| awk -F " " '{print $NF}' \
|
||||||
|
| xargs -r ${CLANG_FORMAT_BIN} -style=file -output-replacements-xml \
|
||||||
|
| grep "replacement offset" 2>&1 > /dev/null
|
||||||
|
|
||||||
|
RET=$?
|
||||||
|
popd > /dev/null
|
||||||
|
|
||||||
|
exit ${RET}
|
||||||
10
04-static-analysis/clang-format/subproject1/CMakeLists.txt
Normal file
10
04-static-analysis/clang-format/subproject1/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Set the project name
|
||||||
|
project (subproject1)
|
||||||
|
|
||||||
|
# Create a sources variable with a link to all cpp files to compile
|
||||||
|
set(SOURCES
|
||||||
|
main1.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add an executable with the above sources
|
||||||
|
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||||
7
04-static-analysis/clang-format/subproject1/main1.cpp
Normal file
7
04-static-analysis/clang-format/subproject1/main1.cpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
std::cout << "Hello Main1!" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
10
04-static-analysis/clang-format/subproject2/CMakeLists.txt
Normal file
10
04-static-analysis/clang-format/subproject2/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Set the project name
|
||||||
|
project (subproject2)
|
||||||
|
|
||||||
|
# Create a sources variable with a link to all cpp files to compile
|
||||||
|
set(SOURCES
|
||||||
|
main2.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add an executable with the above sources
|
||||||
|
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||||
18
04-static-analysis/clang-format/subproject2/main2.cpp
Normal file
18
04-static-analysis/clang-format/subproject2/main2.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
class TestClass {
|
||||||
|
public:
|
||||||
|
TestClass();
|
||||||
|
};
|
||||||
|
|
||||||
|
TestClass::TestClass() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
std::cout << "Hello Main2!" << std::endl;
|
||||||
|
int* x = NULL;
|
||||||
|
std::cout << *x << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user