我正在尝试为 clang-tidy 创建一个自定义 cmake 目标,以检查我的项目。源文件夹看起来像这样:
src/scripts/run-clang-tidy.py
src/.clang-tidy
src/...
到目前为止,我的计划是使用自定义命令将这两个文件复制到构建目录:
add_custom_command(
OUTPUT run-clang-tidy.py .clang-tidy
COMMAND cp ${CMAKE_SOURCE_DIR}/scripts/run-clang-tidy.py ${CMAKE_SOURCE_DIR}/.clang-tidy ${CMAKE_CURRENT_BINARY_DIR})
我现在想使用自定义目标在构建目录(应该是工作目录)中调用
run-clang-tidy.py
,这样我就可以调用:
make lint
应运行
.clang-tidy
中指定的检查。
要使此脚本正常工作,还需要
CMAKE_EXPORT_COMPILE_COMMANDS
选项。我尝试使用以下命令设置它,但它无法识别它:
add_definitions(-DCMAKE_EXPORT_COMPILE_COMMANDS=ON)
对
add_custom_target
的呼叫会是什么样子?
我可以建议另一种方法,不需要额外的 Python 脚本。
首先,我想将
clang-tidy
和 clang-format
集成到自定义 CMake 规则中,所以我首先生成了位于项目根目录的 .clang-tidy
和 .clang-format
文件。
要生成
.clang-tidy
,首先找到适合您的项目的选项,然后执行以下操作:
$> clang-tidy <source-files> -dump-config <tidy-options> -- <compile-options> > .clang-tidy
与
clang-format
类似,您可以使用-style=xxx
选项从默认样式开始,然后转储它。例如,从 LLVM 风格开始:
$> clang-format -style=LLVM -dump-config > .clang-format
然后,根据需要对其进行编辑并正确配置。它应该看起来像这样:
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: true
AlignEscapedNewlinesLeft: false
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AlwaysBreakAfterDefinitionReturnType: false
AlwaysBreakTemplateDeclarations: false
AlwaysBreakBeforeMultilineStrings: false
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BinPackParameters: true
BinPackArguments: true
ColumnLimit: 80
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
DerivePointerAlignment: false
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: false
IndentWrappedFunctionNames: false
IndentFunctionDeclarationAfterType: false
MaxEmptyLinesToKeep: 1
KeepEmptyLinesAtTheStartOfBlocks: true
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
SpacesBeforeTrailingComments: 1
Cpp11BracedListStyle: true
Standard: Cpp11
IndentWidth: 2
TabWidth: 8
UseTab: Never
BreakBeforeBraces: Attach
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpacesInAngles: false
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpaceAfterCStyleCast: false
SpacesInContainerLiterals: true
SpaceBeforeAssignmentOperators: true
ContinuationIndentWidth: 4
CommentPragmas: '^ IWYU pragma:'
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
SpaceBeforeParens: ControlStatements
DisableFormat: false
...
CMake 允许以非常简单的方式定义自定义规则,您只需在文件中编写一组 CMake 命令并调用
add_custom_target()
过程,然后将其包含在 CMakeList.txt
文件中。这就是我们要做的,我们首先在项目的根目录创建一个 cmake/clang-dev-tools.cmake
文件:
# Additional target to perform clang-format/clang-tidy run
# Requires clang-format and clang-tidy
# Get all project files
file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.hpp)
add_custom_target(
clang-format
COMMAND /usr/bin/clang-format
-style=file
-i
${ALL_SOURCE_FILES}
)
add_custom_target(
clang-tidy
COMMAND /usr/bin/clang-tidy
${ALL_SOURCE_FILES}
-config=''
--
-std=c++11
-I${INCLUDE_DIRECTORIES}
)
然后,编辑您
CMakeLists.txt
并添加:
# Including extra cmake rules
include(cmake/clang-dev-tools.cmake)
然后,一旦构建系统重新生成,您应该能够运行
make clang-tidy
和 make clang-format
。
Alexander Shukaev提到的文档在细节上有点简短,所以我添加了一个示例。警告字符串的格式使 IDE 认为 clang-tidy 结果是编译器警告,并将标记源代码。此外,它在创建目标文件后并行运行每个文件。
if ( CMAKE_VERSION GREATER "3.5" )
set(ENABLE_CLANG_TIDY OFF CACHE BOOL "Add clang-tidy automatically to builds")
if (ENABLE_CLANG_TIDY)
find_program (CLANG_TIDY_EXE NAMES "clang-tidy" PATHS /usr/local/opt/llvm/bin )
if (CLANG_TIDY_EXE)
message(STATUS "clang-tidy found: ${CLANG_TIDY_EXE}")
set(CLANG_TIDY_CHECKS "-*,modernize-*")
set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXE};-checks=${CLANG_TIDY_CHECKS};-header-filter='${CMAKE_SOURCE_DIR}/*'"
CACHE STRING "" FORCE)
else()
message(AUTHOR_WARNING "clang-tidy not found!")
set(CMAKE_CXX_CLANG_TIDY "" CACHE STRING "" FORCE) # delete it
endif()
endif()
endif()
我遇到的唯一问题是它仍然检查自动生成的
moc_*.cxx
文件以及
ExternalProject
中代码警告的常见烦恼。
add_definitions
设置CMake 变量,仅在配置阶段可用。如果您想为构建阶段执行的命令设置 environment 变量,请使用带有
COMMAND
关键字的适当 shell 机制:
add_custom_target(lint
COMMAND CMAKE_EXPORT_COMPILE_COMMANDS=ON python run-clang-tidy.py
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/run-clang-tidy.py
${CMAKE_CURRENT_BINARY_DIR}/.clang-tidy
为
COMMAND
关键字指定的所有内容都将由 shell“按原样”解释(在 CMake 解释之后,这里是无操作)。