From ad4eb66fdfb83b3d1502dcaa19b988114b95fb08 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 11 Feb 2025 13:07:36 +1100 Subject: [PATCH] Tools: add OUTPUT_DIR option to the "check_cppcheck" target - Add optional `--build-dir` & `--output-dir` arguments to "static_check_cppcheck.py". - Support using `project_source_info.py` without the CWD having to be the build-directory. - Make the script executable. --- GNUmakefile | 12 +++- tools/check_source/project_source_info.py | 44 +++++++++++---- tools/check_source/static_check_cppcheck.py | 62 ++++++++++++++++++++- 3 files changed, 103 insertions(+), 15 deletions(-) mode change 100644 => 100755 tools/check_source/static_check_cppcheck.py diff --git a/GNUmakefile b/GNUmakefile index c251905cf8d..20a7fcd2ebc 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -56,7 +56,12 @@ Testing Targets Static Source Code Checking Not associated with building Blender. - * check_cppcheck: Run blender source through cppcheck (C & C++). + * check_cppcheck: + Run blender source through cppcheck (C & C++). + + To write log files into a user defined location append 'OUTPUT_DIR', + e.g. 'OUTPUT_DIR=/example/path' + * check_clang_array: Run blender source through clang array checking script (C & C++). * check_struct_comments: Check struct member comments are correct (C & C++). * check_deprecated: Check if there is any deprecated code to remove. @@ -474,9 +479,10 @@ project_eclipse: .FORCE check_cppcheck: .FORCE @$(CMAKE_CONFIG) - @cd "$(BUILD_DIR)" ; \ $(PYTHON) \ - "$(BLENDER_DIR)/tools/check_source/static_check_cppcheck.py" + "$(BLENDER_DIR)/tools/check_source/static_check_cppcheck.py" \ + --build-dir=$(BUILD_DIR) \ + --output-dir=$(OUTPUT_DIR) check_struct_comments: .FORCE @$(CMAKE_CONFIG) diff --git a/tools/check_source/project_source_info.py b/tools/check_source/project_source_info.py index 84da6e0ded2..5047387d059 100644 --- a/tools/check_source/project_source_info.py +++ b/tools/check_source/project_source_info.py @@ -4,8 +4,10 @@ __all__ = ( + "cmake_dir_set", "build_info", "SOURCE_DIR", + "CMAKE_DIR", ) @@ -38,6 +40,19 @@ SOURCE_DIR = join(dirname(__file__), "..", "..") SOURCE_DIR = normpath(SOURCE_DIR) SOURCE_DIR = abspath(SOURCE_DIR) +# copied from project_info.py +CMAKE_DIR = "." + + +def cmake_dir_set(cmake_dir: str) -> None: + """ + Callers may not run this tool from the CWD, in this case, + allow the value to be set. + """ + # Use a method in case any other values need to be updated in the future. + global CMAKE_DIR + CMAKE_DIR = cmake_dir + def is_c_header(filename: str) -> bool: ext = os.path.splitext(filename)[1] @@ -53,10 +68,6 @@ def is_c_any(filename: str) -> bool: return is_c(filename) or is_c_header(filename) -# copied from project_info.py -CMAKE_DIR = "." - - def cmake_cache_var_iter() -> Iterator[tuple[str, str, str]]: import re re_cache = re.compile(r'([A-Za-z0-9_\-]+)?:?([A-Za-z0-9_\-]+)?=(.*)$') @@ -102,14 +113,27 @@ def makefile_log() -> list[str]: if make_exe_basename.startswith(("make", "gmake")): print("running 'make' with --dry-run ...") - process = subprocess.Popen([make_exe, "--always-make", "--dry-run", "--keep-going", "VERBOSE=1"], - stdout=subprocess.PIPE, - ) + process = subprocess.Popen( + ( + make_exe, + "-C", CMAKE_DIR, + "--always-make", + "--dry-run", + "--keep-going", + "VERBOSE=1", + ), + stdout=subprocess.PIPE, + ) elif make_exe_basename.startswith("ninja"): print("running 'ninja' with -t commands ...") - process = subprocess.Popen([make_exe, "-t", "commands"], - stdout=subprocess.PIPE, - ) + process = subprocess.Popen( + ( + make_exe, + "-C", CMAKE_DIR, + "-t", "commands", + ), + stdout=subprocess.PIPE, + ) if process is None: print("Can't execute process") diff --git a/tools/check_source/static_check_cppcheck.py b/tools/check_source/static_check_cppcheck.py old mode 100644 new mode 100755 index dd7d0d5df2f..369bedee81d --- a/tools/check_source/static_check_cppcheck.py +++ b/tools/check_source/static_check_cppcheck.py @@ -3,10 +3,18 @@ # # SPDX-License-Identifier: GPL-2.0-or-later +""" +Run CPPCHECK on Blender's source files, +writing results to a log as well as a summary of all checks. + +Existing logs are renamed to ``.old.log`` so they can be compared. +""" + __all__ = ( "main", ) +import argparse import project_source_info import subprocess import sys @@ -352,9 +360,59 @@ def cppcheck_generate_summary( log_summary_fh.write(line) +def argparse_create() -> argparse.ArgumentParser: + + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawTextHelpFormatter, + ) + + parser.add_argument( + "--build-dir", + dest="build_dir", + metavar='BUILD_DIR', + type=str, + help=( + "The build directory (containing CMakeCache.txt).\n" + "\n" + "Defaults to the \".\"." + ), + default=".", + required=False, + ) + + parser.add_argument( + "--output-dir", + dest="output_dir", + metavar='OUTPUT_DIR', + type=str, + help=( + "Specify the directory where CPPCHECK logs will be written to.\n" + "Using this may be preferred so the build directory can be cleared\n" + "without loosing the result of previous checks.\n" + "\n" + "Defaults to {BUILD_DIR}/cppcheck/" + ), + default="", + required=False, + ) + + return parser + + def main() -> None: - cmake_dir = os.path.normpath(os.path.abspath(project_source_info.CMAKE_DIR)) - cppcheck_dir = os.path.join(cmake_dir, "cppcheck") + args = argparse_create().parse_args() + + project_source_info.cmake_dir_set(args.build_dir) + + cppcheck_dir = args.output_dir + + if cppcheck_dir: + cppcheck_dir = os.path.normpath(os.path.abspath(cppcheck_dir)) + else: + cppcheck_dir = os.path.join(os.path.normpath(os.path.abspath(project_source_info.CMAKE_DIR)), "cppcheck") + + del args filepath_output_log = os.path.join(cppcheck_dir, "cppcheck.part.log") filepath_output_summary_log = os.path.join(cppcheck_dir, "cppcheck_summary.part.log")