From e06ab18a0dc9c885bdfa745f3d68c793544f0cda Mon Sep 17 00:00:00 2001 From: Nicholas Brown Date: Thu, 25 Jun 2015 10:07:34 +0100 Subject: [PATCH] Add useful 'make cppcheck' target. Pulled in the needed cmake modules from rpavlik/cmake-modules and added targets for all libraries. Should be useful for developers looking for potential problems. --- CMakeLists.txt | 5 +- cmake/modules/CppcheckTargets.cmake | 239 +++++++++++++++++++++++++++ cmake/modules/Findcppcheck.cmake | 173 +++++++++++++++++++ cmake/modules/Findcppcheck.cpp | 16 ++ src/common/CMakeLists.txt | 2 + src/common/ipfixlolib/CMakeLists.txt | 1 + src/core/CMakeLists.txt | 1 + src/modules/CMakeLists.txt | 2 +- 8 files changed, 437 insertions(+), 2 deletions(-) create mode 100644 cmake/modules/CppcheckTargets.cmake create mode 100644 cmake/modules/Findcppcheck.cmake create mode 100644 cmake/modules/Findcppcheck.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e9d8932..65f5622 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ PROJECT(VERMONT) ### CMake configuration # allow building with old CMake. Use some bundled modules as a fallback -CMAKE_MINIMUM_REQUIRED(VERSION 2.4) +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules") # TODO: Once all warnings are fixed add -Werror to both of these @@ -56,6 +56,8 @@ MARK_AS_ADVANCED( LIBRARY_OUTPUT_PATH ) +include(CppcheckTargets) + ### basic modules SUBDIRS( @@ -98,6 +100,7 @@ INSTALL(DIRECTORY configs/ DESTINATION share/vermont/configs ) +add_cppcheck(vermont STYLE POSSIBLE_ERROR) ### doxygen diff --git a/cmake/modules/CppcheckTargets.cmake b/cmake/modules/CppcheckTargets.cmake new file mode 100644 index 0000000..7a85fec --- /dev/null +++ b/cmake/modules/CppcheckTargets.cmake @@ -0,0 +1,239 @@ +# - Run cppcheck on c++ source files as a custom target and a test +# +# include(CppcheckTargets) +# add_cppcheck( [UNUSED_FUNCTIONS] [STYLE] [POSSIBLE_ERROR] [FORCE] [FAIL_ON_WARNINGS]) - +# Create a target to check a target's sources with cppcheck and the indicated options +# add_cppcheck_sources( [UNUSED_FUNCTIONS] [STYLE] [POSSIBLE_ERROR] [FORCE] [FAIL_ON_WARNINGS]) - +# Create a target to check standalone sources with cppcheck and the indicated options +# +# Requires these CMake modules: +# Findcppcheck +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__add_cppcheck) + return() +endif() +set(__add_cppcheck YES) + +if(NOT CPPCHECK_FOUND) + find_package(cppcheck QUIET) +endif() + +if(NOT CPPCHECK_FOUND) + add_custom_target(cppcheck + COMMENT "cppcheck executable not found") + set_target_properties(cppcheck PROPERTIES EXCLUDE_FROM_ALL TRUE) +elseif(CPPCHECK_VERSION VERSION_LESS 1.53.0) + add_custom_target(cppcheck + COMMENT "Need at least cppcheck 1.53, found ${CPPCHECK_VERSION}") + set_target_properties(cppcheck PROPERTIES EXCLUDE_FROM_ALL TRUE) + set(CPPCHECK_FOUND) +endif() + +if(NOT TARGET cppcheck) + add_custom_target(cppcheck) +endif() + +function(add_cppcheck_sources _targetname) + if(CPPCHECK_FOUND) + set(_cppcheck_args -I ${CMAKE_SOURCE_DIR} + ${CPPCHECK_EXTRA_ARGS}) + set(_input ${ARGN}) + list(FIND _input UNUSED_FUNCTIONS _unused_func) + if("${_unused_func}" GREATER "-1") + list(APPEND _cppcheck_args ${CPPCHECK_UNUSEDFUNC_ARG}) + list(REMOVE_AT _input ${_unused_func}) + endif() + + list(FIND _input STYLE _style) + if("${_style}" GREATER "-1") + list(APPEND _cppcheck_args ${CPPCHECK_STYLE_ARG}) + list(REMOVE_AT _input ${_style}) + endif() + + list(FIND _input POSSIBLE_ERROR _poss_err) + if("${_poss_err}" GREATER "-1") + list(APPEND _cppcheck_args ${CPPCHECK_POSSIBLEERROR_ARG}) + list(REMOVE_AT _input ${_poss_err}) + endif() + + list(FIND _input FORCE _force) + if("${_force}" GREATER "-1") + list(APPEND _cppcheck_args "--force") + list(REMOVE_AT _input ${_force}) + endif() + + list(FIND _input FAIL_ON_WARNINGS _fail_on_warn) + if("${_fail_on_warn}" GREATER "-1") + list(APPEND + CPPCHECK_FAIL_REGULAR_EXPRESSION + ${CPPCHECK_WARN_REGULAR_EXPRESSION}) + list(REMOVE_AT _input ${_fail_on_warn}) + endif() + + set(_files) + foreach(_source ${_input}) + get_source_file_property(_cppcheck_loc "${_source}" LOCATION) + if(_cppcheck_loc) + # This file has a source file property, carry on. + get_source_file_property(_cppcheck_lang "${_source}" LANGUAGE) + if(("${_cppcheck_lang}" STREQUAL "C") OR ("${_cppcheck_lang}" STREQUAL "CXX")) + list(APPEND _files "${_cppcheck_loc}") + endif() + else() + # This file doesn't have source file properties - figure it out. + get_filename_component(_cppcheck_loc "${_source}" ABSOLUTE) + if(EXISTS "${_cppcheck_loc}") + list(APPEND _files "${_cppcheck_loc}") + else() + message(FATAL_ERROR + "Adding CPPCHECK for file target ${_targetname}: " + "File ${_source} does not exist or needs a corrected path location " + "since we think its absolute path is ${_cppcheck_loc}") + endif() + endif() + endforeach() + + if("1.${CMAKE_VERSION}" VERSION_LESS "1.2.8.0") + # Older than CMake 2.8.0 + add_test(${_targetname}_cppcheck_test + "${CPPCHECK_EXECUTABLE}" + ${CPPCHECK_TEMPLATE_ARG} + ${_cppcheck_args} + ${_files}) + else() + # CMake 2.8.0 and newer + add_test(NAME + ${_targetname}_cppcheck_test + COMMAND + "${CPPCHECK_EXECUTABLE}" + ${CPPCHECK_TEMPLATE_ARG} + ${_cppcheck_args} + ${_files}) + endif() + + set_tests_properties(${_targetname}_cppcheck_test + PROPERTIES + FAIL_REGULAR_EXPRESSION + "${CPPCHECK_FAIL_REGULAR_EXPRESSION}") + + add_custom_target(${_targetname}_cppcheck + COMMAND + ${CPPCHECK_EXECUTABLE} + ${CPPCHECK_QUIET_ARG} + ${CPPCHECK_TEMPLATE_ARG} + ${_cppcheck_args} + ${_files} + WORKING_DIRECTORY + "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT + "${_targetname}_cppcheck: Running cppcheck on target ${_targetname}..." + VERBATIM) + add_dependencies(cppcheck ${_targetname}_cppcheck) + endif() +endfunction() + +function(add_cppcheck _name) + if(NOT TARGET ${_name}) + message(FATAL_ERROR + "add_cppcheck given a target name that does not exist: '${_name}' !") + endif() + if(CPPCHECK_FOUND) + set(_cppcheck_args -I ${CMAKE_SOURCE_DIR} + ${CPPCHECK_EXTRA_ARGS}) + + list(FIND ARGN UNUSED_FUNCTIONS _unused_func) + if("${_unused_func}" GREATER "-1") + list(APPEND _cppcheck_args ${CPPCHECK_UNUSEDFUNC_ARG}) + endif() + + list(FIND ARGN STYLE _style) + if("${_style}" GREATER "-1") + list(APPEND _cppcheck_args ${CPPCHECK_STYLE_ARG}) + endif() + + list(FIND ARGN POSSIBLE_ERROR _poss_err) + if("${_poss_err}" GREATER "-1") + list(APPEND _cppcheck_args ${CPPCHECK_POSSIBLEERROR_ARG}) + endif() + + list(FIND ARGN FORCE _force) + if("${_force}" GREATER "-1") + list(APPEND _cppcheck_args "--force") + endif() + + list(FIND _input FAIL_ON_WARNINGS _fail_on_warn) + if("${_fail_on_warn}" GREATER "-1") + list(APPEND + CPPCHECK_FAIL_REGULAR_EXPRESSION + ${CPPCHECK_WARN_REGULAR_EXPRESSION}) + list(REMOVE_AT _input ${_unused_func}) + endif() + + get_target_property(_cppcheck_includes "${_name}" INCLUDE_DIRECTORIES) + set(_includes) + foreach(_include ${_cppcheck_includes}) + list(APPEND _includes "-I${_include}") + endforeach() + + get_target_property(_cppcheck_sources "${_name}" SOURCES) + set(_files) + foreach(_source ${_cppcheck_sources}) + get_source_file_property(_cppcheck_lang "${_source}" LANGUAGE) + get_source_file_property(_cppcheck_loc "${_source}" LOCATION) + if(("${_cppcheck_lang}" STREQUAL "C") OR ("${_cppcheck_lang}" STREQUAL "CXX")) + list(APPEND _files "${_cppcheck_loc}") + endif() + endforeach() + + if("1.${CMAKE_VERSION}" VERSION_LESS "1.2.8.0") + # Older than CMake 2.8.0 + add_test(${_name}_cppcheck_test + "${CPPCHECK_EXECUTABLE}" + ${CPPCHECK_TEMPLATE_ARG} + ${_cppcheck_args} + ${_files}) + else() + # CMake 2.8.0 and newer + add_test(NAME + ${_name}_cppcheck_test + COMMAND + "${CPPCHECK_EXECUTABLE}" + ${CPPCHECK_TEMPLATE_ARG} + ${_cppcheck_args} + ${_files}) + endif() + + set_tests_properties(${_name}_cppcheck_test + PROPERTIES + FAIL_REGULAR_EXPRESSION + "${CPPCHECK_FAIL_REGULAR_EXPRESSION}") + + add_custom_target(${_name}_cppcheck + COMMAND + ${CPPCHECK_EXECUTABLE} + ${CPPCHECK_QUIET_ARG} + ${CPPCHECK_TEMPLATE_ARG} + ${_cppcheck_args} + ${_includes} + ${_files} + WORKING_DIRECTORY + "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT + "${_name}_cppcheck: Running cppcheck on target ${_name}..." + VERBATIM) + add_dependencies(cppcheck ${_name}_cppcheck) + endif() + +endfunction() diff --git a/cmake/modules/Findcppcheck.cmake b/cmake/modules/Findcppcheck.cmake new file mode 100644 index 0000000..3f13a6b --- /dev/null +++ b/cmake/modules/Findcppcheck.cmake @@ -0,0 +1,173 @@ +# - try to find cppcheck tool +# +# Cache Variables: +# CPPCHECK_EXECUTABLE +# +# Non-cache variables you might use in your CMakeLists.txt: +# CPPCHECK_FOUND +# CPPCHECK_VERSION +# CPPCHECK_POSSIBLEERROR_ARG +# CPPCHECK_UNUSEDFUNC_ARG +# CPPCHECK_STYLE_ARG +# CPPCHECK_QUIET_ARG +# CPPCHECK_INCLUDEPATH_ARG +# CPPCHECK_FAIL_REGULAR_EXPRESSION +# CPPCHECK_WARN_REGULAR_EXPRESSION +# CPPCHECK_MARK_AS_ADVANCED - whether to mark our vars as advanced even +# if we don't find this program. +# +# Requires these CMake modules: +# FindPackageHandleStandardArgs (known included with CMake >=2.6.2) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +file(TO_CMAKE_PATH "${CPPCHECK_ROOT_DIR}" CPPCHECK_ROOT_DIR) +set(CPPCHECK_ROOT_DIR + "${CPPCHECK_ROOT_DIR}" + CACHE + PATH + "Path to search for cppcheck") + +# cppcheck app bundles on Mac OS X are GUI, we want command line only +set(_oldappbundlesetting ${CMAKE_FIND_APPBUNDLE}) +set(CMAKE_FIND_APPBUNDLE NEVER) + +if(CPPCHECK_EXECUTABLE AND NOT EXISTS "${CPPCHECK_EXECUTABLE}") + set(CPPCHECK_EXECUTABLE "notfound" CACHE PATH FORCE "") +endif() + +# If we have a custom path, look there first. +if(CPPCHECK_ROOT_DIR) + find_program(CPPCHECK_EXECUTABLE + NAMES + cppcheck + cli + PATHS + "${CPPCHECK_ROOT_DIR}" + PATH_SUFFIXES + cli + NO_DEFAULT_PATH) +endif() + +find_program(CPPCHECK_EXECUTABLE NAMES cppcheck) + +# Restore original setting for appbundle finding +set(CMAKE_FIND_APPBUNDLE ${_oldappbundlesetting}) + +# Find out where our test file is +get_filename_component(_cppcheckmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) +set(_cppcheckdummyfile "${_cppcheckmoddir}/Findcppcheck.cpp") +if(NOT EXISTS "${_cppcheckdummyfile}") + message(FATAL_ERROR + "Missing file ${_cppcheckdummyfile} - should be alongside Findcppcheck.cmake, can be found at https://github.com/rpavlik/cmake-modules") +endif() + +function(_cppcheck_test_arg _resultvar _arg) + if(NOT CPPCHECK_EXECUTABLE) + set(${_resultvar} NO) + return() + endif() + execute_process(COMMAND + "${CPPCHECK_EXECUTABLE}" + "${_arg}" + "--quiet" + "${_cppcheckdummyfile}" + RESULT_VARIABLE + _cppcheck_result + OUTPUT_QUIET + ERROR_QUIET) + if("${_cppcheck_result}" EQUAL 0) + set(${_resultvar} YES PARENT_SCOPE) + else() + set(${_resultvar} NO PARENT_SCOPE) + endif() +endfunction() + +function(_cppcheck_set_arg_var _argvar _arg) + if("${${_argvar}}" STREQUAL "") + _cppcheck_test_arg(_cppcheck_arg "${_arg}") + if(_cppcheck_arg) + set(${_argvar} "${_arg}" PARENT_SCOPE) + endif() + endif() +endfunction() + +if(CPPCHECK_EXECUTABLE) + + # Check for the two types of command line arguments by just trying them + _cppcheck_set_arg_var(CPPCHECK_STYLE_ARG "--enable=style") + _cppcheck_set_arg_var(CPPCHECK_STYLE_ARG "--style") + if("${CPPCHECK_STYLE_ARG}" STREQUAL "--enable=style") + + _cppcheck_set_arg_var(CPPCHECK_UNUSEDFUNC_ARG + "--enable=unusedFunction") + _cppcheck_set_arg_var(CPPCHECK_INFORMATION_ARG "--enable=information") + _cppcheck_set_arg_var(CPPCHECK_MISSINGINCLUDE_ARG + "--enable=missingInclude") + _cppcheck_set_arg_var(CPPCHECK_POSIX_ARG "--enable=posix") + _cppcheck_set_arg_var(CPPCHECK_POSSIBLEERROR_ARG + "--enable=possibleError") + _cppcheck_set_arg_var(CPPCHECK_POSSIBLEERROR_ARG "--enable=all") + + if(MSVC) + set(CPPCHECK_TEMPLATE_ARG --template vs) + set(CPPCHECK_FAIL_REGULAR_EXPRESSION "[(]error[)]") + set(CPPCHECK_WARN_REGULAR_EXPRESSION "[(]style[)]") + elseif(CMAKE_COMPILER_IS_GNUCXX) + set(CPPCHECK_TEMPLATE_ARG --template gcc) + set(CPPCHECK_FAIL_REGULAR_EXPRESSION " error: ") + set(CPPCHECK_WARN_REGULAR_EXPRESSION " style: ") + else() + set(CPPCHECK_TEMPLATE_ARG --template gcc) + set(CPPCHECK_FAIL_REGULAR_EXPRESSION " error: ") + set(CPPCHECK_WARN_REGULAR_EXPRESSION " style: ") + endif() + elseif("${CPPCHECK_STYLE_ARG}" STREQUAL "--style") + # Old arguments + _cppcheck_set_arg_var(CPPCHECK_UNUSEDFUNC_ARG "--unused-functions") + _cppcheck_set_arg_var(CPPCHECK_POSSIBLEERROR_ARG "--all") + set(CPPCHECK_FAIL_REGULAR_EXPRESSION "error:") + set(CPPCHECK_WARN_REGULAR_EXPRESSION "[(]style[)]") + else() + # No idea - some other issue must be getting in the way + message(STATUS + "WARNING: Can't detect whether CPPCHECK wants new or old-style arguments!") + endif() + + set(CPPCHECK_QUIET_ARG "--quiet") + set(CPPCHECK_INCLUDEPATH_ARG "-I") + +endif() + +set(CPPCHECK_ALL + "${CPPCHECK_EXECUTABLE} ${CPPCHECK_POSSIBLEERROR_ARG} ${CPPCHECK_UNUSEDFUNC_ARG} ${CPPCHECK_STYLE_ARG} ${CPPCHECK_QUIET_ARG} ${CPPCHECK_INCLUDEPATH_ARG} some/include/path") + +execute_process(COMMAND "${CPPCHECK_EXECUTABLE}" --version + OUTPUT_VARIABLE CPPCHECK_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) +string(REGEX REPLACE ".* ([0-9]\\.([0-9]\\.[0-9])?)" "\\1" + CPPCHECK_VERSION "${CPPCHECK_VERSION}") + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(cppcheck + DEFAULT_MSG + CPPCHECK_ALL + CPPCHECK_EXECUTABLE + CPPCHECK_POSSIBLEERROR_ARG + CPPCHECK_UNUSEDFUNC_ARG + CPPCHECK_STYLE_ARG + CPPCHECK_INCLUDEPATH_ARG + CPPCHECK_QUIET_ARG) + +if(CPPCHECK_FOUND OR CPPCHECK_MARK_AS_ADVANCED) + mark_as_advanced(CPPCHECK_ROOT_DIR) +endif() + +mark_as_advanced(CPPCHECK_EXECUTABLE) diff --git a/cmake/modules/Findcppcheck.cpp b/cmake/modules/Findcppcheck.cpp new file mode 100644 index 0000000..84350db --- /dev/null +++ b/cmake/modules/Findcppcheck.cpp @@ -0,0 +1,16 @@ +/** + * \file Findcppcheck.cpp + * \brief Dummy C++ source file used by CMake module Findcppcheck.cmake + * + * \author + * Ryan Pavlik, 2009-2010 + * + * http://academic.cleardefinition.com/ + * + */ + + + +int main(int argc, char* argv[]) { + return 0; +} diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 15356ae..46d323b 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -36,6 +36,8 @@ ADD_LIBRARY(common openssl/SSLCTXWrapper.cpp ) +add_cppcheck(common STYLE POSSIBLE_ERROR) + SUBDIRS( anon ipfixlolib diff --git a/src/common/ipfixlolib/CMakeLists.txt b/src/common/ipfixlolib/CMakeLists.txt index aeb1f4c..c170116 100644 --- a/src/common/ipfixlolib/CMakeLists.txt +++ b/src/common/ipfixlolib/CMakeLists.txt @@ -24,3 +24,4 @@ ADD_LIBRARY(ipfixlolib ipfix_names.c ) +add_cppcheck(ipfixlolib STYLE POSSIBLE_ERROR) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index bd51386..b9be174 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -15,3 +15,4 @@ ADD_LIBRARY(core XMLTextNode.cpp ) +add_cppcheck(core STYLE POSSIBLE_ERROR) diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt index 7d188b4..648dfc3 100644 --- a/src/modules/CMakeLists.txt +++ b/src/modules/CMakeLists.txt @@ -122,4 +122,4 @@ ADD_LIBRARY(modules ipfix/database/IpfixFlowInspectorExporter.cpp ) - +add_cppcheck(modules STYLE POSSIBLE_ERROR)