Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions tools/cmake_cache_audit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env python3
"""Audit CMakeCache.txt for required MACA build configuration keys."""

from __future__ import annotations

import argparse
import json
import sys
import tempfile
from pathlib import Path

REQUIRED = ['MACA_HOME', 'USE_MACA', 'CMAKE_CXX_COMPILER']


def parse_cache(path: Path) -> dict[str, str]:
values: dict[str, str] = {}
for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
line = line.strip()
if not line or line.startswith("//") or line.startswith("#") or "=" not in line:
continue
key_type, value = line.split("=", 1)
key = key_type.split(":", 1)[0].strip()
values[key] = value.strip()
return values
Comment on lines +15 to +24

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current parser does not strip leading or trailing whitespace from lines, keys, or values. If there are leading spaces or spaces around the = delimiter, the parser might fail to identify keys or include unwanted whitespace in the parsed values. Stripping whitespace improves parsing robustness.

Suggested change
def parse_cache(path: Path) -> dict[str, str]:
values: dict[str, str] = {}
for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
if not line or line.startswith("//") or line.startswith("#") or "=" not in line:
continue
key_type, value = line.split("=", 1)
key = key_type.split(":", 1)[0]
values[key] = value
return values
def parse_cache(path: Path) -> dict[str, str]:
values: dict[str, str] = {}
for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
line = line.strip()
if not line or line.startswith("//") or line.startswith("#") or "=" not in line:
continue
key_type, value = line.split("=", 1)
key = key_type.split(":", 1)[0].strip()
values[key] = value.strip()
return values



def audit(path: Path) -> dict[str, object]:
values = parse_cache(path)
missing = [key for key in REQUIRED if not values.get(key)]
return {"ok": not missing, "missing": missing, "values": {key: values.get(key, "") for key in REQUIRED}}


def self_test() -> None:
with tempfile.TemporaryDirectory() as tmp:
sample = Path(tmp) / "CMakeCache.txt"
sample.write_text(" MACA_HOME:PATH = /opt/maca \n", encoding="utf-8")
data = audit(sample)
if "missing" not in data or data["values"]["MACA_HOME"] != "/opt/maca":
raise RuntimeError("self-test failed: cache parser did not normalize values")
print(json.dumps({"ok": True, "missing": len(data["missing"])}, ensure_ascii=False))


def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("cache", nargs="?", default="CMakeCache.txt")
parser.add_argument("--self-test", action="store_true")
args = parser.parse_args()
if args.self_test:
self_test()
return 0
cache = Path(args.cache)
if not cache.is_file():
print(f"CMake cache file not found: {cache}", file=sys.stderr)
return 2
print(json.dumps(audit(cache), ensure_ascii=False, indent=2))
return 0
Comment on lines +43 to +56

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the specified CMake cache file (defaulting to CMakeCache.txt) does not exist, the script will crash with a raw FileNotFoundError traceback. It is better to check if the file exists and print a clean error message to sys.stderr before returning a non-zero exit code.

Suggested change
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("cache", nargs="?", default="CMakeCache.txt")
parser.add_argument("--self-test", action="store_true")
args = parser.parse_args()
if args.self_test:
self_test()
return 0
print(json.dumps(audit(Path(args.cache)), ensure_ascii=False, indent=2))
return 0
def main() -> int:
import sys
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("cache", nargs="?", default="CMakeCache.txt")
parser.add_argument("--self-test", action="store_true")
args = parser.parse_args()
if args.self_test:
self_test()
return 0
cache_path = Path(args.cache)
if not cache_path.is_file():
print(f"Error: CMake cache file not found at '{cache_path}'", file=sys.stderr)
return 1
print(json.dumps(audit(cache_path), ensure_ascii=False, indent=2))
return 0



if __name__ == "__main__":
raise SystemExit(main())