Skip to content

Commit 7a7d44d

Browse files
authored
Add clang format and tidy (#7)
* Add clang format and clang tidy * wip
1 parent ca52ecf commit 7a7d44d

File tree

6 files changed

+412
-0
lines changed

6 files changed

+412
-0
lines changed

.clang-format

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
BasedOnStyle: Mozilla
2+
3+
AccessModifierOffset: '-4'
4+
AlignAfterOpenBracket: BlockIndent
5+
AlignEscapedNewlines: Left
6+
AllowAllArgumentsOnNextLine: false
7+
AllowAllParametersOfDeclarationOnNextLine: false
8+
AllowShortBlocksOnASingleLine: false
9+
AllowShortCaseLabelsOnASingleLine: false
10+
AllowShortFunctionsOnASingleLine: false
11+
AllowShortIfStatementsOnASingleLine: false
12+
# Forbid one line lambdas because clang-format makes a weird split when
13+
# single instructions lambdas are too long.
14+
AllowShortLambdasOnASingleLine: Empty
15+
AllowShortLoopsOnASingleLine: false
16+
AlwaysBreakAfterDefinitionReturnType: None
17+
AlwaysBreakAfterReturnType: None
18+
AlwaysBreakTemplateDeclarations: Yes
19+
BinPackArguments: false
20+
BinPackParameters: false
21+
BreakBeforeBinaryOperators: NonAssignment
22+
BreakBeforeBraces: Allman
23+
BreakBeforeTernaryOperators: true
24+
BreakConstructorInitializers: BeforeComma
25+
BreakInheritanceList: AfterComma
26+
BreakStringLiterals: false
27+
ColumnLimit: '110'
28+
ConstructorInitializerIndentWidth: '4'
29+
ContinuationIndentWidth: '4'
30+
Cpp11BracedListStyle: true
31+
DerivePointerAlignment: false
32+
DisableFormat: false
33+
EmptyLineAfterAccessModifier: Always
34+
EmptyLineBeforeAccessModifier: Always
35+
ExperimentalAutoDetectBinPacking: true
36+
IncludeBlocks: Regroup
37+
IncludeCategories:
38+
- Regex: <[^.]+>
39+
Priority: 1
40+
- Regex: <sparrow/.+>
41+
Priority: 3
42+
- Regex: <.+>
43+
Priority: 2
44+
- Regex: '"sparrow/.+"'
45+
Priority: 4
46+
- Regex: '".+"'
47+
Priority: 5
48+
IndentCaseLabels: true
49+
IndentPPDirectives: AfterHash
50+
IndentWidth: '4'
51+
IndentWrappedFunctionNames: false
52+
InsertBraces: true
53+
InsertTrailingCommas: Wrapped
54+
KeepEmptyLinesAtTheStartOfBlocks: false
55+
LambdaBodyIndentation: Signature
56+
Language: Cpp
57+
MaxEmptyLinesToKeep: '2'
58+
NamespaceIndentation: All
59+
ObjCBlockIndentWidth: '4'
60+
ObjCSpaceAfterProperty: false
61+
ObjCSpaceBeforeProtocolList: false
62+
PackConstructorInitializers: Never
63+
PenaltyBreakAssignment: 100000
64+
PenaltyBreakBeforeFirstCallParameter: 0
65+
PenaltyBreakComment: 10
66+
PenaltyBreakOpenParenthesis: 0
67+
PenaltyBreakTemplateDeclaration: 0
68+
PenaltyExcessCharacter: 10
69+
PenaltyIndentedWhitespace: 0
70+
PenaltyReturnTypeOnItsOwnLine: 10
71+
PointerAlignment: Left
72+
QualifierAlignment: Custom # Experimental
73+
QualifierOrder: [inline, static, constexpr, const, volatile, type]
74+
ReflowComments: true
75+
SeparateDefinitionBlocks: Always
76+
SortIncludes: CaseInsensitive
77+
SortUsingDeclarations: true
78+
SpaceAfterCStyleCast: true
79+
SpaceAfterTemplateKeyword: true
80+
SpaceBeforeAssignmentOperators: true
81+
SpaceBeforeParens: ControlStatements
82+
SpaceInEmptyParentheses: false
83+
SpacesBeforeTrailingComments: '2'
84+
SpacesInAngles: false
85+
SpacesInCStyleCastParentheses: false
86+
SpacesInContainerLiterals: false
87+
SpacesInParentheses: false
88+
SpacesInSquareBrackets: false
89+
Standard: c++20
90+
TabWidth: '4'
91+
UseTab: Never

.clang-tidy

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
Checks: 'clang-diagnostic-*,clang-analyzer-*,cppcoreguidelines-*,modernize-*,performance-*,portability-*,-modernize-use-trailing-return-type'
3+
WarningsAsErrors: ''
4+
HeaderFileExtensions:
5+
- ''
6+
- h
7+
- hh
8+
- hpp
9+
- hxx
10+
ImplementationFileExtensions:
11+
- c
12+
- cc
13+
- cpp
14+
- cxx
15+
HeaderFilterRegex: ''
16+
FormatStyle: file
17+
SystemHeaders: false
18+
...

CMakeLists.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,22 @@ project(sparrow-ipc CXX)
55
set(CMAKE_CXX_STANDARD 20)
66
set(CMAKE_CXX_STANDARD_REQUIRED ON)
77
set(CMAKE_CXX_SCAN_FOR_MODULES OFF)
8+
include(CMakeDependentOption)
89

910
set(SPARROW_IPC_COMPILE_DEFINITIONS "" CACHE STRING "List of public compile definitions of the sparrow-ipc target")
1011

12+
# Linter options
13+
# =============
14+
OPTION(ACTIVATE_LINTER "Create targets to run clang-format" OFF)
15+
MESSAGE(STATUS "🔧 Activate linter: ${ACTIVATE_LINTER}")
16+
cmake_dependent_option(ACTIVATE_LINTER_DURING_COMPILATION "Run linter during the compilation" ON "ACTIVATE_LINTER" OFF)
17+
18+
if(ACTIVATE_LINTER)
19+
include(clang-format)
20+
include(clang-tidy)
21+
endif()
22+
23+
1124
# Build options
1225
# =============
1326

@@ -108,6 +121,11 @@ else()
108121
target_compile_definitions(sparrow-ipc PRIVATE SPARROW_IPC_EXPORTS)
109122
endif()
110123

124+
target_compile_options(sparrow-ipc
125+
PRIVATE
126+
${compile_options}
127+
)
128+
111129
target_include_directories(sparrow-ipc PUBLIC ${SPARROW_IPC_INCLUDE_DIR} PRIVATE ${SPARROW_IPC_SOURCE_DIR} )
112130
target_link_libraries(sparrow-ipc PRIVATE flatbuffers_interface)
113131
target_link_libraries(sparrow-ipc PUBLIC flatbuffers::flatbuffers sparrow::sparrow)

cmake/clang-format.cmake

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
set(CLANG-FORMAT_MINIMUM_MAJOR_VERSION 18)
2+
3+
function(get_clang_format_version clang_format_path)
4+
set(CLANG_FORMAT_VERSION_OUTPUT "")
5+
execute_process(
6+
COMMAND ${clang_format_path} --version
7+
OUTPUT_VARIABLE CLANG_FORMAT_VERSION_OUTPUT
8+
)
9+
string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" CLANG_FORMAT_VERSION_OUTPUT ${CLANG_FORMAT_VERSION_OUTPUT})
10+
set(CLANG_FORMAT_MAJOR_VERSION ${CMAKE_MATCH_1} PARENT_SCOPE)
11+
set(CLANG_FORMAT_MINOR_VERSION ${CMAKE_MATCH_2} PARENT_SCOPE)
12+
set(CLANG_FORMAT_PATCH_VERSION ${CMAKE_MATCH_3} PARENT_SCOPE)
13+
endfunction()
14+
15+
function(check_clang-format_version validator_result_var item)
16+
set(${validator_result_var} FALSE PARENT_SCOPE)
17+
get_clang_format_version(${item})
18+
if (CLANG_FORMAT_MAJOR_VERSION LESS CLANG-FORMAT_MINIMUM_MAJOR_VERSION)
19+
message(DEBUG "clang-format found at ${item} | version: ${CLANG_FORMAT_MAJOR_VERSION}.${CLANG_FORMAT_MINOR_VERSION}.${CLANG_FORMAT_PATCH_VERSION}")
20+
message(DEBUG "but version is lower than ${CLANG-FORMAT_MINIMUM_MAJOR_VERSION}")
21+
set(${validator_result_var} FALSE PARENT_SCOPE)
22+
else()
23+
set(${validator_result_var} TRUE PARENT_SCOPE)
24+
endif()
25+
endfunction()
26+
27+
function(print_clang_format_install_instructions)
28+
message(STATUS "🛠️ Please install clang-format to enable code formatting")
29+
message(STATUS "Can be installed via conda-forge: https://prefix.dev/channels/conda-forge/packages/clang-format")
30+
if(UNIX)
31+
if(APPLE)
32+
message(STATUS "🍎 On MacOS, you can install clang-format with:")
33+
message(STATUS "\t> brew install clang-format")
34+
else()
35+
message(STATUS "🐧 On Ubuntu, you can install clang-format with:")
36+
message(STATUS "\t> sudo apt-get install clang-format")
37+
endif()
38+
elseif(WIN32)
39+
message(STATUS "🪟 On Windows, you can install clang-format with:")
40+
message(STATUS "\t> winget llvm")
41+
endif()
42+
endfunction()
43+
44+
find_program(CLANG_FORMAT clang-format
45+
VALIDATOR check_clang-format_version)
46+
47+
if(NOT CLANG_FORMAT)
48+
message(WARNING "❗ clang-format not found")
49+
50+
print_clang_format_install_instructions()
51+
else()
52+
get_clang_format_version(${CLANG_FORMAT})
53+
message(STATUS "✅ clang-format (version: ${CLANG_FORMAT_MAJOR_VERSION}.${CLANG_FORMAT_MINOR_VERSION}.${CLANG_FORMAT_PATCH_VERSION}) found at ${CLANG_FORMAT}")
54+
55+
# list all files to format
56+
set(
57+
FORMAT_PATTERNS
58+
include/*.hpp
59+
test/*.cpp
60+
test/*.hpp
61+
CACHE STRING
62+
"; separated patterns relative to the project source dir to format"
63+
)
64+
65+
set(ALL_FILES_TO_FORMAT "")
66+
foreach(PATTERN ${FORMAT_PATTERNS})
67+
file(GLOB_RECURSE FILES_TO_FORMAT ${CMAKE_SOURCE_DIR}/${PATTERN})
68+
list(APPEND ALL_FILES_TO_FORMAT ${FILES_TO_FORMAT})
69+
endforeach()
70+
71+
add_custom_target(
72+
clang-format
73+
COMMAND ${CLANG_FORMAT} -i -style=file ${ALL_FILES_TO_FORMAT}
74+
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
75+
COMMENT "Running clang-format on all files"
76+
)
77+
78+
add_custom_target(
79+
clang-format_dry_run
80+
COMMAND ${CLANG_FORMAT} --dry-run -style=file ${ALL_FILES_TO_FORMAT}
81+
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
82+
COMMENT "Running dry clang-format on all files"
83+
)
84+
endif()

cmake/clang-tidy.cmake

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
if(CMAKE_GENERATOR MATCHES "Ninja|Unix Makefiles")
2+
message(STATUS "🔧 CMAKE_EXPORT_COMPILE_COMMANDS will be used to enable clang-tidy")
3+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
4+
else()
5+
message(WARNING "🚧 CMAKE_EXPORT_COMPILE_COMMANDS can't be used because the CMAKE_GENERATOR is ${CMAKE_GENERATOR}.
6+
You have to use Ninja or Unix Makefiles.
7+
Without CMAKE_EXPORT_COMPILE_COMMANDS, clang-tidy will not work.
8+
CMAKE_EXPORT_COMPILE_COMMANDS is used to generate a JSON file that contains all the compiler commands used to build the project.
9+
This file is used by clang-tidy to know how to compile the project.")
10+
endif()
11+
12+
set(CLANG-TIDY_MINIMUM_MAJOR_VERSION 18)
13+
14+
function(get_clang_tidy_version clang_tidy_path)
15+
set(CLANG_TIDY_VERSION_OUTPUT "")
16+
execute_process(
17+
COMMAND ${clang_tidy_path} --version
18+
OUTPUT_VARIABLE CLANG_TIDY_VERSION_OUTPUT
19+
)
20+
string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" CLANG_TIDY_VERSION_OUTPUT ${CLANG_TIDY_VERSION_OUTPUT})
21+
set(CLANG_TIDY_MAJOR_VERSION ${CMAKE_MATCH_1} PARENT_SCOPE)
22+
set(CLANG_TIDY_MINOR_VERSION ${CMAKE_MATCH_2} PARENT_SCOPE)
23+
set(CLANG_TIDY_PATCH_VERSION ${CMAKE_MATCH_3} PARENT_SCOPE)
24+
endfunction()
25+
26+
function(check_clang-tidy_version validator_result_var item)
27+
set(${validator_result_var} FALSE PARENT_SCOPE)
28+
get_clang_tidy_version(${item})
29+
if (CLANG_TIDY_MAJOR_VERSION LESS CLANG-TIDY_MINIMUM_MAJOR_VERSION)
30+
message(DEBUG "clang-tidy (version: ${CLANG_TIDY_MAJOR_VERSION}.${CLANG_TIDY_MINOR_VERSION}.${CLANG_TIDY_PATCH_VERSION}) found at ${item}")
31+
message(DEBUG "but clang-tidy with version >= ${CLANG-TIDY_MINIMUM_MAJOR_VERSION} must be used.")
32+
set(${validator_result_var} FALSE PARENT_SCOPE)
33+
else()
34+
set(${validator_result_var} TRUE PARENT_SCOPE)
35+
endif()
36+
endfunction()
37+
38+
function(print_clang_tidy_install_instructions)
39+
message(STATUS "🛠️ Please install clang-tidy to enable code formatting")
40+
if(UNIX)
41+
if(APPLE)
42+
message(STATUS "🍎 On MacOS, you can install clang-tidy with:")
43+
message(STATUS "\t> brew install clang-tidy")
44+
else()
45+
message(STATUS "🐧 On Ubuntu, you can install clang-tidy with:")
46+
message(STATUS "\t> sudo apt-get install clang-tidy")
47+
endif()
48+
elseif(WIN32)
49+
message(STATUS "🪟 On Windows, you can install clang-tidy with:")
50+
message(STATUS "\t> winget llvm")
51+
endif()
52+
endfunction()
53+
54+
find_program(CLANG_TIDY clang-tidy
55+
VALIDATOR check_clang-tidy_version)
56+
57+
if(NOT CLANG_TIDY)
58+
message(WARNING "❗clang-tidy with version >= ${CLANG-TIDY_MINIMUM_MAJOR_VERSION} not found")
59+
60+
print_clang_tidy_install_instructions()
61+
else()
62+
get_clang_tidy_version(${CLANG_TIDY})
63+
message(STATUS "✅ clang-tidy (version: ${CLANG_TIDY_MAJOR_VERSION}.${CLANG_TIDY_MINOR_VERSION}.${CLANG_TIDY_PATCH_VERSION}) found at ${CLANG_TIDY}")
64+
65+
if(ACTIVATE_LINTER_DURING_COMPILATION)
66+
message(STATUS "🔧 clang-tidy will be activated during compilation")
67+
set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY})
68+
else()
69+
message(STATUS "🔧 clang-tidy will not be activated during compilation")
70+
set(CMAKE_CXX_CLANG_TIDY "")
71+
endif()
72+
73+
find_package (Python COMPONENTS Interpreter)
74+
if(Python_Interpreter_FOUND)
75+
message(DEBUG "Python found at ${Python_EXECUTABLE}")
76+
get_filename_component(CLANG_TIDY_FOLDER ${CLANG_TIDY} DIRECTORY)
77+
find_file(CLANG_TIDY_PYTHON_SCRIPT run-clang-tidy PATHS ${CLANG_TIDY_FOLDER} NO_DEFAULT_PATH)
78+
if(CLANG_TIDY_PYTHON_SCRIPT)
79+
message(DEBUG "run-clang-tidy.py found at ${CLANG_TIDY_PYTHON_SCRIPT}")
80+
endif()
81+
set(CLANG_TIDY_COMMAND ${Python_EXECUTABLE} ${CLANG_TIDY_PYTHON_SCRIPT})
82+
else()
83+
set(CLANG_TIDY_COMMAND ${CLANG_TIDY})
84+
endif()
85+
86+
set(CLANG_TIDY_COMMON_ARGUMENTS
87+
$<$<NOT:$<BOOL:CLANG_TIDY_PYTHON_SCRIPT>>:->-use-color
88+
-p ${CMAKE_BINARY_DIR})
89+
90+
set(
91+
PATTERNS
92+
include/*.hpp
93+
test/*.cpp
94+
test/*.hpp
95+
CACHE STRING
96+
"; separated patterns relative to the project source dir to analyse"
97+
)
98+
99+
set(ALL_FILES_TO_FORMAT "")
100+
foreach(PATTERN ${PATTERNS})
101+
file(GLOB_RECURSE FILES_TO_ANALYZE ${CMAKE_SOURCE_DIR}/${PATTERN})
102+
list(APPEND ALL_FILES_TO_ANALYZE ${FILES_TO_ANALYZE})
103+
endforeach()
104+
105+
add_custom_target(
106+
clang-tidy
107+
COMMAND ${CLANG_TIDY_COMMAND} $<$<NOT:$<BOOL:CLANG_TIDY_PYTHON_SCRIPT>>:->-fix ${CLANG_TIDY_COMMON_ARGUMENTS} ${ALL_FILES_TO_ANALYZE}
108+
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
109+
COMMENT "Running clang-tidy on all files"
110+
)
111+
112+
add_custom_target(
113+
clang-tidy_dry_run
114+
COMMAND ${CLANG_TIDY_COMMAND} ${CLANG_TIDY_COMMON_ARGUMENTS}
115+
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
116+
COMMENT "Running dry clang-tidy on all files"
117+
)
118+
endif()

0 commit comments

Comments
 (0)