1# Copyright (c) 2017-2019, Lawrence Livermore National Security, LLC and 2# other BLT Project Developers. See the top-level COPYRIGHT file for details 3# 4# SPDX-License-Identifier: (BSD-3-Clause) 5#------------------------------------------------------------------------------ 6# Targets related to source code checks (formatting, static analysis, etc) 7#------------------------------------------------------------------------------ 8 9add_custom_target(${BLT_CODE_CHECK_TARGET_NAME}) 10add_custom_target(${BLT_CODE_STYLE_TARGET_NAME}) 11 12if(ASTYLE_FOUND) 13 # targets for verifying formatting 14 add_custom_target(astyle_check) 15 add_dependencies(${BLT_CODE_CHECK_TARGET_NAME} astyle_check) 16 17 # targets for modifying formatting 18 add_custom_target(astyle_style) 19 add_dependencies(${BLT_CODE_STYLE_TARGET_NAME} astyle_style) 20endif() 21 22if(CLANGFORMAT_FOUND) 23 # targets for verifying formatting 24 add_custom_target(clangformat_check) 25 add_dependencies(${BLT_CODE_CHECK_TARGET_NAME} clangformat_check) 26 27 # targets for modifying formatting 28 add_custom_target(clangformat_style) 29 add_dependencies(${BLT_CODE_STYLE_TARGET_NAME} clangformat_style) 30endif() 31 32if(UNCRUSTIFY_FOUND) 33 # targets for verifying formatting 34 add_custom_target(uncrustify_check) 35 add_dependencies(${BLT_CODE_CHECK_TARGET_NAME} uncrustify_check) 36 37 # targets for modifying formatting 38 add_custom_target(uncrustify_style) 39 add_dependencies(${BLT_CODE_STYLE_TARGET_NAME} uncrustify_style) 40endif() 41 42if(CPPCHECK_FOUND) 43 add_custom_target(cppcheck_check) 44 add_dependencies(${BLT_CODE_CHECK_TARGET_NAME} cppcheck_check) 45endif() 46 47if(CLANGQUERY_FOUND) 48 # note: interactive_clang_query_check 49 # is for the use of code developers who 50 # want to check specific attributes of 51 # specific targets, and does not make 52 # sense as a dependency of check 53 add_custom_target(clang_query_check) 54 add_custom_target(interactive_clang_query_check) 55 add_dependencies(${BLT_CODE_CHECK_TARGET_NAME} clang_query_check) 56endif() 57 58# Code check targets should only be run on demand 59foreach(target 60 check uncrustify_check astyle_check clangformat_check cppcheck_check 61 style uncrustify_style astyle_style clangformat_style 62 clang_query_check interactive_clang_query_check) 63 if(TARGET ${target}) 64 set_property(TARGET ${target} PROPERTY EXCLUDE_FROM_ALL TRUE) 65 set_property(TARGET ${target} PROPERTY EXCLUDE_FROM_DEFAULT_BUILD TRUE) 66 endif() 67endforeach() 68 69 70##------------------------------------------------------------------------------ 71## blt_add_code_checks( PREFIX <Base name used for created targets> 72## SOURCES [source1 [source2 ...]] 73## ASTYLE_CFG_FILE <Path to AStyle config file> 74## CLANGFORMAT_CFG_FILE <Path to ClangFormat config file> 75## UNCRUSTIFY_CFG_FILE <Path to Uncrustify config file> 76## CPPCHECK_FLAGS <List of flags added to Cppcheck>) 77## 78## This macro adds all enabled code check targets for the given SOURCES. It 79## filters checks based on file extensions. 80##------------------------------------------------------------------------------ 81 82macro(blt_add_code_checks) 83 84 set(options ) 85 set(singleValueArgs PREFIX ASTYLE_CFG_FILE CLANGFORMAT_CFG_FILE UNCRUSTIFY_CFG_FILE) 86 set(multiValueArgs SOURCES CPPCHECK_FLAGS) 87 88 cmake_parse_arguments(arg 89 "${options}" "${singleValueArgs}" "${multiValueArgs}" ${ARGN}) 90 91 if (NOT DEFINED arg_PREFIX) 92 message(FATAL_ERROR "blt_add_code_checks requires the parameter PREFIX.") 93 endif() 94 95 if (NOT DEFINED arg_SOURCES) 96 message(FATAL_ERROR "blt_add_code_checks requires the parameter SOURCES.") 97 endif() 98 99 # Make the sources relative to the bin directory 100 set(_rel_sources) 101 foreach(_file ${arg_SOURCES}) 102 # Get full path 103 if(IS_ABSOLUTE ${_file}) 104 set(_full_path ${_file}) 105 else() 106 set(_full_path ${CMAKE_CURRENT_SOURCE_DIR}/${_file}) 107 endif() 108 109 file(RELATIVE_PATH _rel_path ${CMAKE_BINARY_DIR} ${_full_path}) 110 list(APPEND _rel_sources ${_rel_path}) 111 endforeach() 112 113 # Generate source lists based on language 114 set(_c_sources) 115 set(_f_sources) 116 blt_split_source_list_by_language(SOURCES ${_rel_sources} 117 C_LIST _c_sources 118 Fortran_LIST _f_sources) 119 120 # Check that at most one formatting config file was supplied 121 if (DEFINED arg_UNCRUSTIFY_CFG_FILE AND DEFINED arg_ASTYLE_CFG_FILE) 122 message(FATAL_ERROR 123 "blt_add_code_checks macro does not support multiple " 124 "style config parameters within the same invocation. " 125 "Both UNCRUSTIFY_CFG_FILE and ASTYLE_CFG_FILE were supplied.") 126 endif() 127 128 # Add code checks 129 set(_error_msg "blt_add_code_checks tried to create an already existing target with given PREFIX: ${arg_PREFIX}. ") 130 131 if (ASTYLE_FOUND AND DEFINED arg_ASTYLE_CFG_FILE) 132 set(_check_target_name ${arg_PREFIX}_astyle_check) 133 blt_error_if_target_exists(${_check_target_name} ${_error_msg}) 134 set(_style_target_name ${arg_PREFIX}_astyle_style) 135 blt_error_if_target_exists(${_style_target_name} ${_error_msg}) 136 137 blt_add_astyle_target( NAME ${_check_target_name} 138 MODIFY_FILES FALSE 139 CFG_FILE ${arg_ASTYLE_CFG_FILE} 140 WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 141 SRC_FILES ${_c_sources} ) 142 143 blt_add_astyle_target( NAME ${_style_target_name} 144 MODIFY_FILES TRUE 145 CFG_FILE ${arg_ASTYLE_CFG_FILE} 146 WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 147 SRC_FILES ${_c_sources} ) 148 endif() 149 150 if (CLANGFORMAT_FOUND AND DEFINED arg_CLANGFORMAT_CFG_FILE) 151 set(_check_target_name ${arg_PREFIX}_clangformat_check) 152 blt_error_if_target_exists(${_check_target_name} ${_error_msg}) 153 set(_style_target_name ${arg_PREFIX}_clangformat_style) 154 blt_error_if_target_exists(${_style_target_name} ${_error_msg}) 155 156 blt_add_clangformat_target( NAME ${_check_target_name} 157 MODIFY_FILES FALSE 158 CFG_FILE ${arg_CLANGFORMAT_CFG_FILE} 159 WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 160 SRC_FILES ${_c_sources} ) 161 162 blt_add_clangformat_target( NAME ${_style_target_name} 163 MODIFY_FILES TRUE 164 CFG_FILE ${arg_CLANGFORMAT_CFG_FILE} 165 WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 166 SRC_FILES ${_c_sources} ) 167 endif() 168 169 if (UNCRUSTIFY_FOUND AND DEFINED arg_UNCRUSTIFY_CFG_FILE) 170 set(_check_target_name ${arg_PREFIX}_uncrustify_check) 171 blt_error_if_target_exists(${_check_target_name} ${_error_msg}) 172 set(_style_target_name ${arg_PREFIX}_uncrustify_style) 173 blt_error_if_target_exists(${_style_target_name} ${_error_msg}) 174 175 blt_add_uncrustify_target( NAME ${_check_target_name} 176 MODIFY_FILES FALSE 177 CFG_FILE ${arg_UNCRUSTIFY_CFG_FILE} 178 WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 179 SRC_FILES ${_c_sources} ) 180 181 blt_add_uncrustify_target( NAME ${_style_target_name} 182 MODIFY_FILES TRUE 183 CFG_FILE ${arg_UNCRUSTIFY_CFG_FILE} 184 WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 185 SRC_FILES ${_c_sources} ) 186 endif() 187 188 if (CPPCHECK_FOUND) 189 set(_cppcheck_target_name ${arg_PREFIX}_cppcheck_check) 190 blt_error_if_target_exists(${_cppcheck_target_name} ${_error_msg}) 191 192 blt_add_cppcheck_target( NAME ${_cppcheck_target_name} 193 WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 194 SRC_FILES ${_c_sources} 195 PREPEND_FLAGS ${arg_CPPCHECK_FLAGS}) 196 endif() 197 198 if (CLANGQUERY_FOUND) 199 set(_clang_query_target_name ${arg_PREFIX}_clang_query_check) 200 blt_error_if_target_exists(${_clang_query_target_name} ${_error_msg}) 201 blt_add_clang_query_target( NAME ${_clang_query_target_name} 202 WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 203 SRC_FILES ${_c_sources}) 204 endif() 205 206endmacro(blt_add_code_checks) 207 208##----------------------------------------------------------------------------- 209## blt_add_clang_query_target( NAME <Created Target Name> 210## WORKING_DIRECTORY <Working Directory> 211## COMMENT <Additional Comment for Target Invocation> 212## CHECKERS <If specified, requires a specific set of checkers> 213## DIE_ON_MATCH <If true, matches stop the build> 214## SRC_FILES [FILE1 [FILE2 ...]] ) 215## 216## Creates a new target with the given NAME for running clang_query over the given SRC_FILES 217##----------------------------------------------------------------------------- 218macro(blt_add_clang_query_target) 219 if(CLANGQUERY_FOUND) 220 221 ## parse the arguments to the macro 222 set(options) 223 set(singleValueArgs NAME COMMENT WORKING_DIRECTORY DIE_ON_MATCH) 224 set(multiValueArgs SRC_FILES CHECKERS) 225 226 cmake_parse_arguments(arg 227 "${options}" "${singleValueArgs}" "${multiValueArgs}" ${ARGN} ) 228 229 # Check required parameters 230 if(NOT DEFINED arg_NAME) 231 message(FATAL_ERROR "blt_add_clang_query_target requires a NAME parameter") 232 endif() 233 234 if(NOT DEFINED arg_SRC_FILES) 235 message(FATAL_ERROR "blt_add_clang_query_target requires a SRC_FILES parameter") 236 endif() 237 238 if(DEFINED arg_WORKING_DIRECTORY) 239 set(_wd ${arg_WORKING_DIRECTORY}) 240 else() 241 set(_wd ${CMAKE_CURRENT_SOURCE_DIR}) 242 endif() 243 244 set(interactive_target_name interactive_${arg_NAME}) 245 set(CLANG_QUERY_HELPER_SCRIPT ${BLT_ROOT_DIR}/cmake/clang-query-wrapper.py) 246 set(CLANG_QUERY_HELPER_COMMAND python ${CLANG_QUERY_HELPER_SCRIPT} --clang-query ${CLANGQUERY_EXECUTABLE} --checker-directories ${BLT_CLANG_QUERY_CHECKER_DIRECTORIES} --compilation-database-path ${CMAKE_BINARY_DIR}) 247 248 if(arg_DIE_ON_MATCH) 249 set(CLANG_QUERY_HELPER_COMMAND ${CLANG_QUERY_HELPER_COMMAND} --die-on-match) 250 endif() 251 252 if(DEFINED arg_CHECKERS) 253 STRING(REGEX REPLACE " " ":" CHECKER_ARG_STRING ${arg_CHECKERS}) 254 add_custom_target(${arg_NAME} 255 COMMAND ${CLANG_QUERY_HELPER_COMMAND} -i --checkers=${CHECKER_ARG_STRING} ${arg_SRC_FILES} 256 WORKING_DIRECTORY ${_wd} 257 COMMENT "${arg_COMMENT}Running specified clang_query source code static analysis checks.") 258 else() #DEFINED CHECKERS 259 add_custom_target(${arg_NAME} 260 COMMAND ${CLANG_QUERY_HELPER_COMMAND} ${arg_SRC_FILES} 261 WORKING_DIRECTORY ${_wd} 262 COMMENT "${arg_COMMENT}Running all clang_query source code static analysis checks.") 263 endif() 264 265 add_custom_target(${interactive_target_name} 266 COMMAND ${CLANG_QUERY_HELPER_COMMAND} -i ${arg_SRC_FILES} 267 WORKING_DIRECTORY ${_wd} 268 COMMENT "${arg_COMMENT}Running clang_query source code static analysis checks.") 269 270 # hook our new target into the proper dependency chain 271 add_dependencies(clang_query_check ${arg_NAME}) 272 add_dependencies(interactive_clang_query_check ${interactive_target_name}) 273 274 # Code check targets should only be run on demand 275 set_property(TARGET ${interactive_target_name} PROPERTY EXCLUDE_FROM_ALL TRUE) 276 set_property(TARGET ${interactive_target_name} PROPERTY EXCLUDE_FROM_DEFAULT_BUILD TRUE) 277 set_property(TARGET ${arg_NAME} PROPERTY EXCLUDE_FROM_ALL TRUE) 278 set_property(TARGET ${arg_NAME} PROPERTY EXCLUDE_FROM_DEFAULT_BUILD TRUE) 279 endif() 280endmacro(blt_add_clang_query_target) 281 282 283##----------------------------------------------------------------------------- 284## blt_add_cppcheck_target( NAME <Created Target Name> 285## WORKING_DIRECTORY <Working Directory> 286## PREPEND_FLAGS <additional flags for cppcheck> 287## APPEND_FLAGS <additional flags for cppcheck> 288## COMMENT <Additional Comment for Target Invocation> 289## SRC_FILES [FILE1 [FILE2 ...]] ) 290## 291## Creates a new target with the given NAME for running cppcheck over the given SRC_FILES 292##----------------------------------------------------------------------------- 293macro(blt_add_cppcheck_target) 294 295 ## parse the arguments to the macro 296 set(options) 297 set(singleValueArgs NAME COMMENT WORKING_DIRECTORY) 298 set(multiValueArgs SRC_FILES PREPEND_FLAGS APPEND_FLAGS) 299 300 cmake_parse_arguments(arg 301 "${options}" "${singleValueArgs}" "${multiValueArgs}" ${ARGN} ) 302 303 # Check required parameters 304 if(NOT DEFINED arg_NAME) 305 message(FATAL_ERROR "blt_add_cppcheck_target requires a NAME parameter") 306 endif() 307 308 if(NOT DEFINED arg_SRC_FILES) 309 message(FATAL_ERROR "blt_add_cppcheck_target requires a SRC_FILES parameter") 310 endif() 311 312 if(DEFINED arg_WORKING_DIRECTORY) 313 set(_wd ${arg_WORKING_DIRECTORY}) 314 else() 315 set(_wd ${CMAKE_CURRENT_SOURCE_DIR}) 316 endif() 317 318 add_custom_target(${arg_NAME} 319 COMMAND ${CPPCHECK_EXECUTABLE} ${arg_PREPEND_FLAGS} ${arg_SRC_FILES} ${arg_APPEND_FLAGS} 320 WORKING_DIRECTORY ${_wd} 321 COMMENT "${arg_COMMENT}Running cppcheck source code static analysis checks.") 322 323 # hook our new target into the proper dependency chain 324 add_dependencies(cppcheck_check ${arg_NAME}) 325 326 # Code check targets should only be run on demand 327 set_property(TARGET ${arg_NAME} PROPERTY EXCLUDE_FROM_ALL TRUE) 328 set_property(TARGET ${arg_NAME} PROPERTY EXCLUDE_FROM_DEFAULT_BUILD TRUE) 329endmacro(blt_add_cppcheck_target) 330 331 332##------------------------------------------------------------------------------ 333## blt_add_astyle_target( NAME <Created Target Name> 334## MODIFY_FILES [TRUE | FALSE (default)] 335## CFG_FILE <AStyle Configuration File> 336## PREPEND_FLAGS <Additional Flags to AStyle> 337## APPEND_FLAGS <Additional Flags to AStyle> 338## COMMENT <Additional Comment for Target Invocation> 339## WORKING_DIRECTORY <Working Directory> 340## SRC_FILES [FILE1 [FILE2 ...]] ) 341## 342## Creates a new target with the given NAME for running astyle over the given SRC_FILES. 343##------------------------------------------------------------------------------ 344macro(blt_add_astyle_target) 345 346 ## parse the arguments to the macro 347 set(options) 348 set(singleValueArgs NAME MODIFY_FILES CFG_FILE COMMENT WORKING_DIRECTORY) 349 set(multiValueArgs SRC_FILES PREPEND_FLAGS APPEND_FLAGS) 350 351 cmake_parse_arguments(arg 352 "${options}" "${singleValueArgs}" "${multiValueArgs}" ${ARGN} ) 353 354 # Check/Set required parameters 355 if(NOT DEFINED arg_NAME) 356 message(FATAL_ERROR "blt_add_astyle_target requires a NAME parameter") 357 endif() 358 359 if(NOT DEFINED arg_CFG_FILE) 360 message(FATAL_ERROR "blt_add_astyle_target requires a CFG_FILE parameter") 361 endif() 362 363 if(NOT DEFINED arg_SRC_FILES) 364 message(FATAL_ERROR "blt_add_astyle_target requires a SRC_FILES parameter") 365 endif() 366 367 if(NOT DEFINED arg_MODIFY_FILES) 368 set(arg_MODIFY_FILES FALSE) 369 endif() 370 371 if(DEFINED arg_WORKING_DIRECTORY) 372 set(_wd ${arg_WORKING_DIRECTORY}) 373 else() 374 set(_wd ${CMAKE_CURRENT_SOURCE_DIR}) 375 endif() 376 377 set(_generate_target TRUE) 378 379 if(${arg_MODIFY_FILES}) 380 set(MODIFY_FILES_FLAG --suffix=none) 381 else() 382 set(MODIFY_FILES_FLAG --dry-run) 383 384 # Check the version -- output is of the form "Artistic Style Version X.Y.Z" 385 execute_process( 386 COMMAND ${ASTYLE_EXECUTABLE} --version 387 OUTPUT_VARIABLE _version_str 388 ERROR_VARIABLE _version_str 389 OUTPUT_STRIP_TRAILING_WHITESPACE ) 390 string(REGEX MATCH "([0-9]+(\\.)?)+$" _astyle_version ${_version_str}) 391 392 # Skip 'check' target if version is not high enough 393 if(_astyle_version VERSION_LESS 2.05) 394 set(_generate_target FALSE) 395 message(WARNING "blt_add_astyle_target requires AStyle v2.05 or greater " 396 " for style check targets. " 397 " Current AStyle executable: '${ASTYLE_EXECUTABLE}' " 398 " Current AStyle version is: ${_astyle_version}." ) 399 endif() 400 endif() 401 402 if(_generate_target) 403 404 # AStyle doesn't report failure when there are files that require formatting. 405 # Fix this with a wrapper script that parses the output. 406 set(wrapped_astyle_script ${CMAKE_CURRENT_BINARY_DIR}/WrapAstyle_${arg_NAME}.cmake) 407 408 configure_file( 409 ${BLT_ROOT_DIR}/cmake/WrapAstyle.cmake.in 410 ${wrapped_astyle_script} 411 @ONLY ) 412 413 add_custom_target( 414 ${arg_NAME} 415 COMMAND ${CMAKE_COMMAND} -P ${wrapped_astyle_script} 416 WORKING_DIRECTORY ${_wd} 417 COMMENT "${arg_COMMENT}Running AStyle source code formatting checks.") 418 419 # Hook our new target into the proper dependency chain 420 if(${arg_MODIFY_FILES}) 421 add_dependencies(astyle_style ${arg_NAME}) 422 else() 423 add_dependencies(astyle_check ${arg_NAME}) 424 endif() 425 426 # Code formatting targets should only be run on demand 427 set_property(TARGET ${arg_NAME} PROPERTY EXCLUDE_FROM_ALL TRUE) 428 set_property(TARGET ${arg_NAME} PROPERTY EXCLUDE_FROM_DEFAULT_BUILD TRUE) 429 endif() 430endmacro(blt_add_astyle_target) 431 432##------------------------------------------------------------------------------ 433## blt_add_clangformat_target( NAME <Created Target Name> 434## MODIFY_FILES [TRUE | FALSE (default)] 435## CFG_FILE <ClangFormat Configuration File> 436## PREPEND_FLAGS <Additional Flags to ClangFormat> 437## APPEND_FLAGS <Additional Flags to ClangFormat> 438## COMMENT <Additional Comment for Target Invocation> 439## WORKING_DIRECTORY <Working Directory> 440## SRC_FILES [FILE1 [FILE2 ...]] ) 441## 442## Creates a new target with the given NAME for running ClangFormat over the given SRC_FILES. 443##------------------------------------------------------------------------------ 444macro(blt_add_clangformat_target) 445 446 ## parse the arguments to the macro 447 set(options) 448 set(singleValueArgs NAME MODIFY_FILES CFG_FILE COMMENT WORKING_DIRECTORY) 449 set(multiValueArgs SRC_FILES PREPEND_FLAGS APPEND_FLAGS) 450 451 cmake_parse_arguments(arg 452 "${options}" "${singleValueArgs}" "${multiValueArgs}" ${ARGN} ) 453 454 # Check/Set required parameters 455 if(NOT DEFINED arg_NAME) 456 message(FATAL_ERROR "blt_add_clangformat_target requires a NAME parameter") 457 endif() 458 459 if(NOT DEFINED arg_CFG_FILE) 460 message(FATAL_ERROR "blt_add_clangformat_target requires a CFG_FILE parameter") 461 endif() 462 463 if(NOT DEFINED arg_SRC_FILES) 464 message(FATAL_ERROR "blt_add_clangformat_target requires a SRC_FILES parameter") 465 endif() 466 467 if(NOT DEFINED arg_MODIFY_FILES) 468 set(arg_MODIFY_FILES FALSE) 469 endif() 470 471 if(DEFINED arg_WORKING_DIRECTORY) 472 set(_wd ${arg_WORKING_DIRECTORY}) 473 else() 474 set(_wd ${CMAKE_CURRENT_SOURCE_DIR}) 475 endif() 476 477 set(_generate_target TRUE) 478 479 # Copy config file to given working directory since ClangFormat doesn't support pointing to one 480 configure_file(${arg_CFG_FILE} ${arg_WORKING_DIRECTORY}/.clang-format COPYONLY) 481 482 if(_generate_target) 483 # ClangFormat does not support --dry-run until version 10 which isn't on many machines. 484 # For now, use run-clang-format for dry running purposes. 485 if(${arg_MODIFY_FILES}) 486 add_custom_target(${arg_NAME} 487 COMMAND ${CLANGFORMAT_EXECUTABLE} ${arg_PREPEND_FLAGS} 488 --style=file -i ${arg_SRC_FILES} ${arg_APPEND_FLAGS} 489 WORKING_DIRECTORY ${_wd} 490 COMMENT "${arg_COMMENT}Running ClangFormat source code formatting checks.") 491 else() 492 set(_run_clangformat "${BLT_ROOT_DIR}/cmake/run-clang-format.py" --clang-format-executable ${CLANGFORMAT_EXECUTABLE}) 493 add_custom_target(${arg_NAME} 494 COMMAND ${_run_clangformat} -j1 ${arg_SRC_FILES} 495 WORKING_DIRECTORY ${_wd} 496 COMMENT "${arg_COMMENT}Running ClangFormat source code formatting checks.") 497 498 endif() 499 500 # Hook our new target into the proper dependency chain 501 if(${arg_MODIFY_FILES}) 502 add_dependencies(clangformat_style ${arg_NAME}) 503 else() 504 add_dependencies(clangformat_check ${arg_NAME}) 505 endif() 506 507 # Code formatting targets should only be run on demand 508 set_property(TARGET ${arg_NAME} PROPERTY EXCLUDE_FROM_ALL TRUE) 509 set_property(TARGET ${arg_NAME} PROPERTY EXCLUDE_FROM_DEFAULT_BUILD TRUE) 510 endif() 511endmacro(blt_add_clangformat_target) 512 513##------------------------------------------------------------------------------ 514## blt_add_uncrustify_target( NAME <Created Target Name> 515## MODIFY_FILES [TRUE | FALSE (default)] 516## CFG_FILE <Uncrustify Configuration File> 517## PREPEND_FLAGS <Additional Flags to Uncrustify> 518## APPEND_FLAGS <Additional Flags to Uncrustify> 519## COMMENT <Additional Comment for Target Invocation> 520## WORKING_DIRECTORY <Working Directory> 521## SRC_FILES [FILE1 [FILE2 ...]] ) 522## 523## Creates a new target with the given NAME for running uncrustify over the given SRC_FILES. 524##------------------------------------------------------------------------------ 525macro(blt_add_uncrustify_target) 526 527 ## parse the arguments to the macro 528 set(options) 529 set(singleValueArgs NAME MODIFY_FILES CFG_FILE COMMENT WORKING_DIRECTORY) 530 set(multiValueArgs SRC_FILES PREPEND_FLAGS APPEND_FLAGS) 531 532 cmake_parse_arguments(arg 533 "${options}" "${singleValueArgs}" "${multiValueArgs}" ${ARGN} ) 534 535 # Check/Set required parameters 536 if(NOT DEFINED arg_NAME) 537 message(FATAL_ERROR "blt_add_uncrustify_target requires a NAME parameter") 538 endif() 539 540 if(NOT DEFINED arg_CFG_FILE) 541 message(FATAL_ERROR "blt_add_uncrustify_target requires a CFG_FILE parameter") 542 endif() 543 544 if(NOT DEFINED arg_SRC_FILES) 545 message(FATAL_ERROR "blt_add_uncrustify_target requires a SRC_FILES parameter") 546 endif() 547 548 if(NOT DEFINED arg_MODIFY_FILES) 549 set(arg_MODIFY_FILES FALSE) 550 endif() 551 552 if(DEFINED arg_WORKING_DIRECTORY) 553 set(_wd ${arg_WORKING_DIRECTORY}) 554 else() 555 set(_wd ${CMAKE_CURRENT_SOURCE_DIR}) 556 endif() 557 558 set(_generate_target TRUE) 559 560 if(${arg_MODIFY_FILES}) 561 set(MODIFY_FILES_FLAG --replace;--no-backup) 562 else() 563 set(MODIFY_FILES_FLAG "--check") 564 565 # Check the version -- output is of the form "uncrustify X.Y.Z" 566 execute_process( 567 COMMAND ${UNCRUSTIFY_EXECUTABLE} --version 568 OUTPUT_VARIABLE _version_str 569 OUTPUT_STRIP_TRAILING_WHITESPACE ) 570 string(REGEX MATCH "([0-9]+(\\.)?)+(_[a-zA-Z])?" _uncrustify_version ${_version_str}) 571 572 # Skip 'check' target if version is not high enough 573 if(_uncrustify_version VERSION_LESS 0.61) 574 set(_generate_target FALSE) 575 message(WARNING "blt_add_uncrustify_target requires uncrustify v0.61 or greater " 576 " for style check targets. " 577 " Current uncrustify executable: '${UNCRUSTIFY_EXECUTABLE}' " 578 " Current uncrustify version is: ${_uncrustify_version}." ) 579 endif() 580 endif() 581 582 if(_generate_target) 583 add_custom_target(${arg_NAME} 584 COMMAND ${UNCRUSTIFY_EXECUTABLE} ${arg_PREPEND_FLAGS} 585 -c ${arg_CFG_FILE} ${MODIFY_FILES_FLAG} ${arg_SRC_FILES} ${arg_APPEND_FLAGS} 586 WORKING_DIRECTORY ${_wd} 587 COMMENT "${arg_COMMENT}Running uncrustify source code formatting checks.") 588 589 # hook our new target into the proper dependency chain 590 if(${arg_MODIFY_FILES}) 591 add_dependencies(uncrustify_style ${arg_NAME}) 592 else() 593 add_dependencies(uncrustify_check ${arg_NAME}) 594 endif() 595 596 # Code formatting targets should only be run on demand 597 set_property(TARGET ${arg_NAME} PROPERTY EXCLUDE_FROM_ALL TRUE) 598 set_property(TARGET ${arg_NAME} PROPERTY EXCLUDE_FROM_DEFAULT_BUILD TRUE) 599 endif() 600 601endmacro(blt_add_uncrustify_target) 602