aheinecke@1: # - Generate a cppcheck documentation for a project. aheinecke@1: # The function GENERATE_CPPCHECK is provided to create a "cppcheck" target that aheinecke@1: # performs static code analysis using the cppcheck utility program. aheinecke@1: # aheinecke@1: # GENERATE_CPPCHECK(SOURCES aheinecke@1: # [SUPPRESSION_FILE ] aheinecke@1: # [ENABLE_IDS ] aheinecke@1: # [TARGET_NAME ] aheinecke@1: # [INCLUDES ]) aheinecke@1: # aheinecke@1: # Generates a target "cppcheck" that executes cppcheck on the specified sources. aheinecke@1: # Sources may either be file names or directories containing files where all aheinecke@1: # C++ files will be parsed automatically. Use directories whenever possible aheinecke@1: # because there is a limitation in arguments to pass to the cppcheck binary. aheinecke@1: # SUPPRESSION_FILE may be give additionally to specify suppressions for# aheinecke@1: # cppcheck. The sources mentioned in the suppression file must be in the same aheinecke@1: # format like given for SOURCES. This means if you specified them relative to aheinecke@1: # CMAKE_CURRENT_SOURCE_DIR, then the same relative paths must be used in the aheinecke@1: # suppression file. aheinecke@1: # ENABLE_IDS allows to specify which additional cppcheck check ids to execute, aheinecke@1: # e.g. all or style. They are combined with AND. aheinecke@1: # With TARGET_NAME a different name for the generated check target can be aheinecke@1: # specified. This is useful if several calles to this function are made in one aheinecke@1: # CMake project, as otherwise the target names collide. aheinecke@1: # Additional include directories for the cppcheck program can be given with aheinecke@1: # INCLUDES. aheinecke@1: # aheinecke@1: # cppcheck will be executed with CMAKE_CURRENT_SOURCE_DIR as working directory. aheinecke@1: # aheinecke@1: # This function can always be called, even if no cppcheck was found. Then no aheinecke@1: # target is created. aheinecke@1: # aheinecke@1: # Copyright (C) 2011 by Johannes Wienke aheinecke@1: # aheinecke@1: # This program is free software; you can redistribute it aheinecke@1: # and/or modify it under the terms of the GNU General aheinecke@1: # Public License as published by the Free Software Foundation; aheinecke@1: # either version 2, or (at your option) aheinecke@1: # any later version. aheinecke@1: # aheinecke@1: # This program is distributed in the hope that it will be useful, aheinecke@1: # but WITHOUT ANY WARRANTY; without even the implied warranty of aheinecke@1: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the aheinecke@1: # GNU General Public License for more details. aheinecke@1: # aheinecke@1: aheinecke@1: GET_FILENAME_COMPONENT(GENERATE_CPPCHECK_MODULE_DIR ${CMAKE_CURRENT_LIST_FILE} PATH) aheinecke@1: aheinecke@1: # FIND_PACKAGE(Cppcheck) aheinecke@1: find_program(CPPCHECK_EXECUTABLE aheinecke@1: cppcheck aheinecke@1: ) aheinecke@1: aheinecke@1: if(CPPCHECK_EXECUTABLE) aheinecke@1: set(CPPCHECK_FOUND True) aheinecke@1: endif() aheinecke@1: aheinecke@1: include(ParseArguments) aheinecke@1: aheinecke@1: FUNCTION(GENERATE_CPPCHECK) aheinecke@1: aheinecke@1: IF(CPPCHECK_FOUND) aheinecke@1: aheinecke@1: PARSE_ARGUMENTS(ARG "SOURCES;SUPPRESSION_FILE;ENABLE_IDS;TARGET_NAME;INCLUDES" "" ${ARGN}) aheinecke@1: aheinecke@1: SET(TARGET_NAME "cppcheck") aheinecke@1: SET(TARGET_NAME_SUFFIX "") aheinecke@1: # parse target name aheinecke@1: LIST(LENGTH ARG_TARGET_NAME TARGET_NAME_LENGTH) aheinecke@1: IF(${TARGET_NAME_LENGTH} EQUAL 1) aheinecke@1: SET(TARGET_NAME ${ARG_TARGET_NAME}) aheinecke@1: SET(TARGET_NAME_SUFFIX "-${ARG_TARGET_NAME}") aheinecke@1: ENDIF() aheinecke@1: aheinecke@1: SET(CPPCHECK_CHECKFILE "${CMAKE_BINARY_DIR}/cppcheck-files${TARGET_NAME_SUFFIX}") aheinecke@1: SET(CPPCHECK_REPORT_FILE "${CMAKE_BINARY_DIR}/cppcheck-report${TARGET_NAME_SUFFIX}.xml") aheinecke@1: SET(CPPCHECK_WRAPPER_SCRIPT "${CMAKE_BINARY_DIR}/cppcheck${TARGET_NAME_SUFFIX}.cmake") aheinecke@1: aheinecke@1: # write a list file containing all sources to check for the call to aheinecke@1: # cppcheck aheinecke@1: SET(SOURCE_ARGS "") aheinecke@1: FOREACH(SOURCE ${ARG_SOURCES}) aheinecke@1: SET(SOURCE_ARGS "${SOURCE_ARGS} \"${SOURCE}\"") aheinecke@1: ENDFOREACH() aheinecke@1: aheinecke@1: # prepare a cmake wrapper to write the stderr output of cppcheck to aheinecke@1: # the result file aheinecke@1: aheinecke@1: # suppression argument aheinecke@1: LIST(LENGTH ARG_SUPPRESSION_FILE SUPPRESSION_FILE_LENGTH) aheinecke@1: IF(${SUPPRESSION_FILE_LENGTH} EQUAL 1) aheinecke@1: GET_FILENAME_COMPONENT(ABS "${ARG_SUPPRESSION_FILE}" ABSOLUTE) aheinecke@1: MESSAGE(STATUS "Using suppression file ${ABS}") aheinecke@1: SET(SUPPRESSION_ARGUMENT --suppressions) aheinecke@1: SET(SUPPRESSION_FILE "\"${ABS}\"") aheinecke@1: ENDIF() aheinecke@1: aheinecke@1: # includes aheinecke@1: SET(INCLUDE_ARGUMENTS "") aheinecke@1: FOREACH(INCLUDE ${ARG_INCLUDES}) aheinecke@1: SET(INCLUDE_ARGUMENTS "${INCLUDE_ARGUMENTS} \"-I${INCLUDE}\"") aheinecke@1: ENDFOREACH() aheinecke@1: aheinecke@1: # enabled ids aheinecke@1: SET(ID_LIST "") aheinecke@1: FOREACH(ID ${ARG_ENABLE_IDS}) aheinecke@1: SET(ID_LIST "${ID_LIST},${ID}") aheinecke@1: ENDFOREACH() aheinecke@1: IF(ID_LIST) aheinecke@1: STRING(LENGTH ${ID_LIST} LIST_LENGTH) aheinecke@1: MATH(EXPR FINAL_LIST_LENGTH "${LIST_LENGTH} - 1") aheinecke@1: STRING(SUBSTRING ${ID_LIST} 1 ${FINAL_LIST_LENGTH} FINAL_ID_LIST) aheinecke@1: SET(IDS_ARGUMENT "\"--enable=${FINAL_ID_LIST}\"") aheinecke@1: ELSE() aheinecke@1: SET(IDS_ARGUMENT "") aheinecke@1: ENDIF() aheinecke@1: aheinecke@1: FILE(WRITE ${CPPCHECK_WRAPPER_SCRIPT} aheinecke@1: " aheinecke@1: EXECUTE_PROCESS(COMMAND \"${CPPCHECK_EXECUTABLE}\" ${INCLUDE_ARGUMENTS} ${SUPPRESSION_ARGUMENT} ${SUPPRESSION_FILE} ${IDS_ARGUMENT} --inline-suppr --xml ${SOURCE_ARGS} aheinecke@1: RESULT_VARIABLE CPPCHECK_EXIT_CODE aheinecke@1: ERROR_VARIABLE ERROR_OUT aheinecke@1: WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\") aheinecke@1: IF(NOT CPPCHECK_EXIT_CODE EQUAL 0) aheinecke@1: MESSAGE(FATAL_ERROR \"Error executing cppcheck for target ${TARGET}, return code: \${CPPCHECK_EXIT_CODE}\") aheinecke@1: ENDIF() aheinecke@1: IF(ERROR_OUT) aheinecke@1: MESSAGE(\"Detected errors:\\n\${ERROR_OUT}\") aheinecke@1: ENDIF() aheinecke@1: FILE(WRITE \"${CPPCHECK_REPORT_FILE}\" \"\${ERROR_OUT}\") aheinecke@1: " aheinecke@1: ) aheinecke@1: aheinecke@1: ADD_CUSTOM_TARGET(${TARGET_NAME} ${CMAKE_COMMAND} -P "${CPPCHECK_WRAPPER_SCRIPT}" aheinecke@1: COMMENT "Generating cppcheck result ${TARGET_NAME}") aheinecke@1: aheinecke@1: MESSAGE(STATUS "Generating cppcheck target with name ${TARGET_NAME}") aheinecke@1: aheinecke@1: ENDIF() aheinecke@1: aheinecke@1: ENDFUNCTION()