diff --git a/.gitignore b/.gitignore index efe05a2..95ea652 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .git/ repo/ .venv/ +__pycache__/ # agents .claude/ diff --git a/cppcheck/build.sh b/cppcheck/build.sh new file mode 100755 index 0000000..e9915a9 --- /dev/null +++ b/cppcheck/build.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -e + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" +cd "$DIR" + +VERSION="2.19.1" +INSTALL_DIR="$DIR/cppcheck/install" + +# Idempotent: skip if already built +if [ -x "$INSTALL_DIR/cppcheck" ]; then + echo "cppcheck already present, skipping build." + exit 0 +fi + +NJOBS="$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 2)" + +# Clone +if [ ! -d "cppcheck-src" ]; then + git clone --depth 1 --branch "$VERSION" https://github.com/danmar/cppcheck.git cppcheck-src +fi + +# Build +cd cppcheck-src +make MATCHCOMPILER=yes CXXFLAGS="-O2" -j"$NJOBS" +cd "$DIR" + +# Install +rm -rf "$INSTALL_DIR" +mkdir -p "$INSTALL_DIR" + +cp cppcheck-src/cppcheck "$INSTALL_DIR/" +cp -r cppcheck-src/addons "$INSTALL_DIR/" +cp -r cppcheck-src/cfg "$INSTALL_DIR/" +cp -r cppcheck-src/platforms "$INSTALL_DIR/" +strip "$INSTALL_DIR/cppcheck" 2>/dev/null || true + +# Clean up +rm -rf cppcheck-src + +echo "Installed cppcheck to $INSTALL_DIR" +du -sh "$INSTALL_DIR" diff --git a/cppcheck/cppcheck/__init__.py b/cppcheck/cppcheck/__init__.py new file mode 100644 index 0000000..dce7db8 --- /dev/null +++ b/cppcheck/cppcheck/__init__.py @@ -0,0 +1,16 @@ +import os +import sys + +DIR = os.path.join(os.path.dirname(__file__), "install") + + +def _run(): + binary = os.path.join(DIR, "cppcheck") + os.execvp(binary, ["cppcheck"] + sys.argv[1:]) + + +def smoketest(): + import subprocess + binary = os.path.join(DIR, "cppcheck") + result = subprocess.run([binary, "--version"], capture_output=True, text=True, check=True) + print(result.stdout.strip()) diff --git a/cppcheck/pyproject.toml b/cppcheck/pyproject.toml new file mode 100644 index 0000000..6ef849f --- /dev/null +++ b/cppcheck/pyproject.toml @@ -0,0 +1,18 @@ +[build-system] +requires = ["setuptools>=64", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "cppcheck" +version = "2.19.1" +description = "Cppcheck static analysis tool" +requires-python = ">=3.8" + +[project.scripts] +cppcheck = "cppcheck:_run" + +[tool.setuptools.packages.find] +include = ["cppcheck*"] + +[tool.setuptools.package-data] +cppcheck = ["install/**/*"] diff --git a/cppcheck/setup.py b/cppcheck/setup.py new file mode 100644 index 0000000..42cde09 --- /dev/null +++ b/cppcheck/setup.py @@ -0,0 +1,61 @@ +import os +import platform +import subprocess + +from setuptools.command.build_py import build_py + +try: + from wheel.bdist_wheel import bdist_wheel +except ImportError: + bdist_wheel = None + + +class BuildCppcheck(build_py): + """Run build.sh to compile cppcheck before collecting package data.""" + + def run(self): + pkg_dir = os.path.dirname(os.path.abspath(__file__)) + marker = os.path.join(pkg_dir, "cppcheck", "install", "cppcheck") + + if not os.path.exists(marker): + build_script = os.path.join(pkg_dir, "build.sh") + subprocess.check_call(["bash", build_script], cwd=pkg_dir) + + super().run() + + +cmdclass = {"build_py": BuildCppcheck} + +if bdist_wheel is not None: + + class PlatformWheel(bdist_wheel): + """Produce a platform-specific, Python-version-agnostic wheel.""" + + def finalize_options(self): + super().finalize_options() + self.root_is_pure = False + + def get_tag(self): + system = platform.system() + machine = platform.machine() + + if system == "Linux": + plat = f"linux_{machine}" + elif system == "Darwin": + plat = "macosx_11_0_arm64" + else: + plat = f"{system.lower()}_{machine}" + + return "py3", "none", plat + + cmdclass["bdist_wheel"] = PlatformWheel + + +def setup(): + from setuptools import setup as _setup + + _setup(cmdclass=cmdclass) + + +if __name__ == "__main__": + setup()