algorithm-finder / src /compiler.py
Michael Arana
Fix Space pipeline failures: g++ via packages.txt, chat_completion with fallback, clear auth errors, Windows exe fix, non-gated default model
2898fad
Raw History Blame Contribute Delete
4.56 kB
import os
import subprocess
import time
import psutil
import tempfile
import shutil
class CppCompiler:
def __init__(self, workdir: str = None):
self.workdir = workdir or tempfile.mkdtemp(prefix="algo_finder_")
os.makedirs(self.workdir, exist_ok=True)
def compile(self, filename: str, source_code: str) -> dict:
if shutil.which("g++") is None:
return {
"compiled": False,
"binary_path": None,
"compile_error": "g++ not found. On Hugging Face Spaces add 'g++' to packages.txt; locally install a C++ toolchain (e.g. 'apt install g++').",
"compile_stderr": "",
}
source_path = os.path.join(self.workdir, f"{filename}.cpp")
binary_path = os.path.join(self.workdir, filename)
if os.name == "nt" and not binary_path.lower().endswith(".exe"):
binary_path = binary_path + ".exe"
with open(source_path, "w", encoding="utf-8") as f:
f.write(source_code)
compile_cmd = ["g++", "-std=c++17", "-O2", source_path, "-o", binary_path]
try:
compile_result = subprocess.run(
compile_cmd,
capture_output=True,
text=True,
timeout=60,
)
except subprocess.TimeoutExpired:
return {
"compiled": False,
"binary_path": None,
"compile_error": "Compilation timed out (60s limit)",
"compile_stderr": "",
}
except FileNotFoundError as e:
return {
"compiled": False,
"binary_path": None,
"compile_error": f"g++ executable not found: {e}. Install g++ (packages.txt on Spaces).",
"compile_stderr": "",
}
except OSError as e:
return {
"compiled": False,
"binary_path": None,
"compile_error": f"Compilation failed to start: {e}",
"compile_stderr": "",
}
if compile_result.returncode != 0:
return {
"compiled": False,
"binary_path": None,
"compile_error": compile_result.stderr.strip(),
"compile_stderr": compile_result.stderr.strip(),
}
return {
"compiled": True,
"binary_path": binary_path,
"compile_error": None,
"compile_stderr": None,
}
def run(self, binary_path: str, timeout: int = 30) -> dict:
if not binary_path or not os.path.exists(binary_path):
return {
"ran": False,
"returncode": None,
"stdout": "",
"stderr": "Binary not found",
"execution_time_s": None,
"memory_kb": None,
}
process = psutil.Process()
start_time = time.perf_counter()
try:
run_result = subprocess.run(
[binary_path],
capture_output=True,
text=True,
timeout=timeout,
)
end_time = time.perf_counter()
execution_time = end_time - start_time
try:
mem_info = process.memory_info()
memory_kb = mem_info.rss / 1024
except Exception:
memory_kb = None
return {
"ran": True,
"returncode": run_result.returncode,
"stdout": run_result.stdout.strip(),
"stderr": run_result.stderr.strip(),
"execution_time_s": round(execution_time, 6),
"memory_kb": round(memory_kb, 2) if memory_kb is not None else None,
}
except subprocess.TimeoutExpired:
return {
"ran": False,
"returncode": None,
"stdout": "",
"stderr": f"Execution timed out ({timeout}s limit)",
"execution_time_s": timeout,
"memory_kb": None,
}
except Exception as e:
return {
"ran": False,
"returncode": None,
"stdout": "",
"stderr": str(e),
"execution_time_s": None,
"memory_kb": None,
}
def cleanup(self):
if os.path.exists(self.workdir):
shutil.rmtree(self.workdir, ignore_errors=True)