mirror of
https://github.com/ttroy50/cmake-examples.git
synced 2025-12-18 12:14: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