import os import shutil import subprocess from conan import ConanFile class FoldConan(ConanFile): name = "fold" version = "0.1.0" license = "GPL-3.0-only" author = "Trevon Williams" description = ( "C++ SAST for duplicate code and dead branches via symbolic execution." ) topics = ("sast", "static-analysis", "clang", "z3", "clone-detection") settings = "os", "compiler", "build_type", "arch" options = { "build_tests": [True, False], "build_mcp_server": [True, False], "build_lsp_server": [True, False], } default_options = { "build_tests": False, "build_mcp_server": True, "build_lsp_server": True, } generators = ("MesonToolchain", "PkgConfigDeps", "CMakeDeps") def _find_tool(self, cmd, version_flag="--version"): path = shutil.which(cmd) if path is None: return None, None try: result = subprocess.run( [path, version_flag], capture_output=True, text=True, timeout=10, ) ver = result.stdout.strip().splitlines()[0] return path, ver except Exception: return path, "detect:unknown" def _find_llvm_config(self): for ver in (22, 21, 20, 19, 18, 17, 16): for name in ( f"llvm-config-{ver}", f"llvm-config{ver}", "llvm-config", ): path, llvm_ver = self._find_tool(name, "--version") if path is not None: self.output.info(f" system LLVM {llvm_ver} → {path}") return True return False def system_requirements(self): have_llvm = self._find_llvm_config() if not have_llvm: self.output.warning( "No system LLVM/Clang found (llvm-config).\n" "Install with: brew install llvm@22\n" "Or: sudo apt install llvm-22-dev clang-22" ) def requirements(self): self.requires("spdlog/1.13.0") self.requires("cli11/2.4.1") self.requires("nlohmann_json/3.11.3") self.requires("sqlite3/3.44.2") self.requires("catch2/3.4.0") # xxhash: SIMD-accelerated hashing (XXH3, AVX2/NEON) for the IR # normalize/hash paths. Header-only usage via XXH_INLINE_ALL. self.requires("xxhash/0.8.3") # rapidfuzz-cpp: bit-parallel Myers Levenshtein with SSE2/AVX2/NEON # tiers and banded score_cutoff variants. Header-only; used by the # clone detector's Type-3/cluster scoring. self.requires("rapidfuzz/3.3.3") # Z3 comes from the system (brew/apt), not Conan. meson.build # finds it via pkg-config. ConanCenter's z3 recipe is unreliable # across platforms. def build_requirements(self): self.tool_requires("pkgconf/2.1.0") self.tool_requires("meson/[>=1.2.2 <2]") self.tool_requires("ninja/[>=1.10.2 <2]")