【问题标题】:cmake clang-tidy (or other script) as custom targetcmake clang-tidy (或其他脚本)作为自定义目标
【发布时间】:2015-11-23 16:27:45
【问题描述】:

我正在尝试为 clang-tidy 创建一个自定义 cmake 目标,以对我的项目进行 lint。源文件夹如下所示:

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 的调用会是什么样子?

【问题讨论】:

  • CMAKE_EXPORT_COMPILE_COMMANDS 是一个 CMake 变量。当设置为 ON 时,它会生成一个文件:“compile_commands.json”,clang 工具可以使用该文件。它不是编译器预处理器宏。 tl;博士:set (CMAKE_EXPORT_COMPILE_COMMANDS ON).

标签: cmake clang target lint clang-tidy


【解决方案1】:

自 CMake 3.6 起,实现了 clang-tidy 的原生集成 [1, 2]。机制类似于自 CMake 3.3 [3] 以来的 include-what-you-use 集成。

【讨论】:

  • 看起来这只适用于 makefile 和 ninja 生成器,不适用于 XCode 或 Visual Studio。所以,没有我希望的那么有用。
【解决方案2】:

我可以建议另一种方法,不需要额外的 Python 脚本。

首先,我想在自定义CMake规则中集成clang-tidy和clang-format,所以我首先生成了位于项目根目录下的.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 允许以非常简单的方式定义自定义规则,您只需在文件中编写一组 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
        ${INCLUDE_DIRECTORIES}
)

然后,编辑你 CMakeLists.txt 并添加:

# Including extra cmake rules
include(cmake/clang-dev-tools.cmake)

然后,一旦构建系统重新生成,您应该能够运行 make clang-tidy 和 make clang-format。

【讨论】:

  • 这主要工作,但它不会检测到我的包含目录
  • 遇到同样的问题,cmake规则中缺少一个参数,应该是-I${INCLUDE_DIRECTORIES}而不是${INCLUDE_DIRECTORIES}
【解决方案3】:

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 中代码的常见警告。

【讨论】:

  • if语句要换成"if (CMAKE_VERSION VERSION_GREATER "3.5" )",否则cmake 3.10及更高版本不会通过。
【解决方案4】:

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 之后,这里是无操作的)。

【讨论】:

  • 为了复制文件,我想我可以使用file(...) 命令?
  • 您原来的add_sustom_command() 似乎可以正确复制文件。但如果你愿意,你可以使用file(...) 命令来达到这个目的。
  • 我认为file 命令会更便携?还是我应该使用cmake -E?
  • 是的,file 命令比cp 更便携。 cmake -E shell 命令也是可移植的。但是,在我的答案中指定环境变量的方式已经降低了可移植性(a=1 do_something 在 Windows 上不起作用)。如果您将项目使用限制为 Linux(或类 Unix 操作系统),则可以使用 cp(而且速度很快)。如果您希望您的项目在 Windows 下运行,则需要以 Windows 特定的方式设置环境变量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-26
  • 1970-01-01
  • 1970-01-01
  • 2021-01-14
  • 1970-01-01
相关资源
最近更新 更多