cmake clang-tidy (или другой скрипт) в качестве пользовательской цели

Я пытаюсь создать пользовательскую цель cmake для clang-tidy, чтобы Линт моего проекта. Исходная папка выглядит примерно так:

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.

для работы этого скрипта также требуется . Я пытаюсь установить его с помощью следующей команды, но он не признает этого:

add_definitions(-DCMAKE_EXPORT_COMPILE_COMMANDS=ON)

как бы назвать add_custom_target выглядеть?

4 ответов


начиная с CMake 3.6, встроенная интеграция clang-tidy реализуется [1, 2]. Механика похожа на include-what-you-use интеграция, которая была там с CMake 3.3 [3].


я могу предложить другой способ, который не требует дополнительного скрипта на 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 позволяют определить пользовательские правила очень простым способом, вам просто нужно написать набор команд CMake в файле с вызовом add_custom_target() процедура и, затем, включите ее в ваш . Это то, что мы будем делать, мы сначала создадим 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.


add_definitions set CMake переменная, доступный только этап конфигурации. Если вы хотите установить окружающая среда переменная для команды, выполняемой на этапе сборки, используйте соответствующий механизм оболочки с COMMAND ключевые слова:

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 ключевое слово будет интерпретироваться оболочкой "как есть" (после интерпретации CMake, которая здесь отсутствует).


документация, упомянутая Александр Шукаев немного не хватает деталей, поэтому я добавляю пример. Форматирование предупреждающих строк заставляет IDEs думать, что результаты 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.