From 0849eaebbfe6cf08a2a7f52ff79cc3e9cc4f0657 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 16 Sep 2011 06:58:20 +0000 Subject: new convenience makefile targets for static source code cheching: check_splint/check_sparse/check_cppcheck --- GNUmakefile | 19 +++ build_files/cmake/cmake_static_check_cppcheck.py | 73 ++++++++++ build_files/cmake/cmake_static_check_sparse.py | 66 +++++++++ build_files/cmake/cmake_static_check_splint.py | 94 +++++++++++++ build_files/cmake/project_source_info.py | 165 +++++++++++++++++++++++ 5 files changed, 417 insertions(+) create mode 100644 build_files/cmake/cmake_static_check_cppcheck.py create mode 100644 build_files/cmake/cmake_static_check_sparse.py create mode 100644 build_files/cmake/cmake_static_check_splint.py create mode 100644 build_files/cmake/project_source_info.py diff --git a/GNUmakefile b/GNUmakefile index 8446541cfae..7da60ce951b 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -126,6 +126,11 @@ help: @echo " * test_pep8 - checks all python script are pep8 which are tagged to use the stricter formatting" @echo " * test_deprecated - checks for deprecation tags in our code which may need to be removed" @echo "" + @echo "Static Source Code Checking (not assosiated with building blender)" + @echo " * check_cppcheck - run blender source through cppcheck (C & C++)" + @echo " * check_splint - run blenders source through splint (C only)" + @echo " * check_sparse - run blenders source through sparse (C only)" + @echo "" # ----------------------------------------------------------------------------- # Packages @@ -176,6 +181,20 @@ project_eclipse: cmake -G"Eclipse CDT4 - Unix Makefiles" -H$(BLENDER_DIR) -B$(BUILD_DIR) +# ----------------------------------------------------------------------------- +# Static Checking +# + +check_cppcheck: + cd $(BUILD_DIR) ; python3 $(BLENDER_DIR)/build_files/cmake/cmake_static_check_cppcheck.py + +check_splint: + cd $(BUILD_DIR) ; python3 $(BLENDER_DIR)/build_files/cmake/cmake_static_check_splint.py + +check_sparse: + cd $(BUILD_DIR) ; python3 $(BLENDER_DIR)/build_files/cmake/cmake_static_check_sparse.py + + clean: $(MAKE) -C $(BUILD_DIR) clean diff --git a/build_files/cmake/cmake_static_check_cppcheck.py b/build_files/cmake/cmake_static_check_cppcheck.py new file mode 100644 index 00000000000..9b03bbf3982 --- /dev/null +++ b/build_files/cmake/cmake_static_check_cppcheck.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python + +# $Id: +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Contributor(s): Campbell Barton +# +# ***** END GPL LICENSE BLOCK ***** + +# + +CHECKER_IGNORE_PREFIX = [ + "extern", + "intern/moto", + ] + +CHECKER_BIN = "cppcheck" + +CHECKER_ARGS = [ + "-I/dsk/data/src/blender/blender/extern/glew/include", + # "--check-config", # when includes are missing + # "--enable=all", # if you want sixty hundred pedantic suggestions + ] + +import project_source_info +import subprocess +import sys + +def main(): + source_info = project_source_info.build_info(ignore_prefix_list=CHECKER_IGNORE_PREFIX) + + check_commands = [] + for c, inc_dirs, defs in source_info: + cmd = ([CHECKER_BIN] + + CHECKER_ARGS + + [c] + + [("-I%s" % i) for i in inc_dirs] + + [("-D%s" % d) for d in defs] + ) + + check_commands.append((c, cmd)) + + for i, (c, cmd) in enumerate(check_commands): + percent = 100.0 * (i / (len(check_commands)-1)) + percent_str = "[" + ("%.2f]" % percent).rjust(7) + " %:" + + # if percent < 27.9: + # continue + + # let cppcheck finish the line off... + sys.stdout.write("%s " % percent_str) + + sys.stdout.flush() + process = subprocess.Popen(cmd) + process.wait() + + +if __name__ == "__main__": + main() diff --git a/build_files/cmake/cmake_static_check_sparse.py b/build_files/cmake/cmake_static_check_sparse.py new file mode 100644 index 00000000000..8b300548c42 --- /dev/null +++ b/build_files/cmake/cmake_static_check_sparse.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python + +# $Id: +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Contributor(s): Campbell Barton +# +# ***** END GPL LICENSE BLOCK ***** + +# + +CHECKER_IGNORE_SUFFIX = [ + "extern", + "intern/moto", + ] + +CHECKER_BIN = "sparse" +CHECKER_ARGS = [ + ] + +import project_source_info +import subprocess +import sys + + +def main(): + source_info = project_source_info.build_info(use_cxx=False, ignore_prefix_list=CHECKER_IGNORE_PREFIX) + + check_commands = [] + for c, inc_dirs, defs in source_info: + + cmd = ([CHECKER_BIN] + + CHECKER_ARGS + + [c] + + [("-I%s" % i) for i in inc_dirs] + + [("-D%s" % d) for d in defs] + ) + + check_commands.append((c, cmd)) + + for i, (c, cmd) in enumerate(check_commands): + percent = 100.0 * (i / (len(check_commands) - 1)) + percent_str = "[" + ("%.2f]" % percent).rjust(7) + " %:" + + sys.stdout.write("%s %s\n" % (percent_str, c)) + sys.stdout.flush() + + process = subprocess.Popen(cmd) + process.wait() + +if __name__ == "__main__": + main() diff --git a/build_files/cmake/cmake_static_check_splint.py b/build_files/cmake/cmake_static_check_splint.py new file mode 100644 index 00000000000..fbbee2351db --- /dev/null +++ b/build_files/cmake/cmake_static_check_splint.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +# $Id: +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Contributor(s): Campbell Barton +# +# ***** END GPL LICENSE BLOCK ***** + +# + +CHECKER_IGNORE_PREFIX = [ + "extern", + "intern/moto", + ] + +CHECKER_BIN = "splint" + +CHECKER_ARGS = [ + "-weak", + "-posix-lib", + "-linelen", "10000", + "+ignorequals", + "+relaxtypes", + "-retvalother", + "+matchanyintegral", + "+longintegral", + "+ignoresigns", + "-nestcomment", + "-predboolothers", + "-ifempty", + "-unrecogcomments", + + # we may want to remove these later + "-type", + "-fixedformalarray", + "-fullinitblock", + "-fcnuse", + "-initallelements", + "-castfcnptr", + # -forcehints, + "-bufferoverflowhigh", # warns a lot about sprintf() + + # re-definitions, rna causes most of these + "-redef", + "-syntax", + ] + + +import project_source_info +import subprocess +import sys + + +def main(): + source_info = project_source_info.build_info(use_cxx=False, ignore_prefix_list=CHECKER_IGNORE_PREFIX) + + check_commands = [] + for c, inc_dirs, defs in source_info: + cmd = ([CHECKER_BIN] + + CHECKER_ARGS + + [c] + + [("-I%s" % i) for i in inc_dirs] + + [("-D%s" % d) for d in defs] + ) + + check_commands.append((c, cmd)) + + for i, (c, cmd) in enumerate(check_commands): + percent = 100.0 * (i / (len(check_commands) - 1)) + percent_str = "[" + ("%.2f]" % percent).rjust(7) + " %:" + + sys.stdout.write("%s %s\n" % (percent_str, c)) + sys.stdout.flush() + + process = subprocess.Popen(cmd) + process.wait() + +if __name__ == "__main__": + main() diff --git a/build_files/cmake/project_source_info.py b/build_files/cmake/project_source_info.py new file mode 100644 index 00000000000..d85544b732f --- /dev/null +++ b/build_files/cmake/project_source_info.py @@ -0,0 +1,165 @@ +# $Id: +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Contributor(s): Campbell Barton +# +# ***** END GPL LICENSE BLOCK ***** + +# + +__all__ = ( + "build_info", + "SOURCE_DIR", + ) + +import os +import sys +from os.path import join, dirname, normpath, abspath + +SOURCE_DIR = join(dirname(__file__), "..", "..") +SOURCE_DIR = normpath(SOURCE_DIR) +SOURCE_DIR = abspath(SOURCE_DIR) + + +def is_c_header(filename): + ext = os.path.splitext(filename)[1] + return (ext in (".h", ".hpp", ".hxx")) + + +def is_c_header(filename): + ext = os.path.splitext(filename)[1] + return (ext in (".h", ".hpp", ".hxx")) + + +def is_c(filename): + ext = os.path.splitext(filename)[1] + return (ext in (".c", ".cpp", ".cxx", ".m", ".mm", ".rc")) + + +def is_c_any(filename): + return os.path.s_c(filename) or is_c_header(filename) + + +# copied from project_info.py +CMAKE_DIR = "." + + +def cmake_cache_var(var): + cache_file = open(join(CMAKE_DIR, "CMakeCache.txt")) + lines = [l_strip for l in cache_file for l_strip in (l.strip(),) if l_strip if not l_strip.startswith("//") if not l_strip.startswith("#")] + cache_file.close() + + for l in lines: + if l.split(":")[0] == var: + return l.split("=", 1)[-1] + return None + + +def do_ignore(filepath, ignore_prefix_list): + if ignore_prefix_list is None: + return False + + relpath = os.path.relpath(filepath, SOURCE_DIR) + return any([relpath.startswith(prefix) for prefix in ignore_prefix_list]) + + +def makefile_log(): + import subprocess + # Check blender is not 2.5x until it supports playback again + print("running make with --dry-run ...") + process = subprocess.Popen(["make", "--always-make", "--dry-run", "--keep-going", "VERBOSE=1"], + stdout=subprocess.PIPE, + ) + + while process.poll(): + time.sleep(1) + + out = process.stdout.read() + process.stdout.close() + print("done!", len(out), "bytes") + return out.decode("ascii").split("\n") + + +def build_info(use_c=True, use_cxx=True, ignore_prefix_list=None): + + makelog = makefile_log() + + source = [] + + compilers = [] + if use_c: + compilers.append(cmake_cache_var("CMAKE_C_COMPILER")) + if use_cxx: + compilers.append(cmake_cache_var("CMAKE_CXX_COMPILER")) + + print("compilers:", " ".join(compilers)) + + fake_compiler = "%COMPILER%" + + print("parsing make log ...") + + for line in makelog: + + args = line.split() + + if not any([(c in args) for c in compilers]): + continue + + # join args incase they are not. + args = ' '.join(args) + args = args.replace(" -isystem", " -I") + args = args.replace(" -D ", " -D") + args = args.replace(" -I ", " -I") + + for c in compilers: + args = args.replace(c, fake_compiler) + args = args.split() + # end + + # remove compiler + args[:args.index(fake_compiler) + 1] = [] + + c_files = [f for f in args if is_c(f)] + inc_dirs = [f[2:].strip() for f in args if f.startswith('-I')] + defs = [f[2:].strip() for f in args if f.startswith('-D')] + for c in sorted(c_files): + + if do_ignore(c, ignore_prefix_list): + continue + + source.append((c, inc_dirs, defs)) + + # safety check that our includes are ok + for f in inc_dirs: + if not os.path.exists(f): + raise Exception("%s missing" % f) + + print("done!") + + return source + + +def main(): + if not os.path.exists(join(CMAKE_DIR, "CMakeCache.txt")): + print("This script must run from the cmake build dir") + return + + for s in build_info(): + print(s) + +if __name__ == "__main__": + main() -- cgit v1.2.3