For-upload-folder / fixcudn.py
ixelszy's picture
Create fixcudn.py
3217396 verified
#!/usr/bin/env python3
# fix_isotropic3d_deps.py
# Otomasi perbaikan libigl (igl) & (opsional) tinycudann untuk Isotropic3D/threestudio.
import os
import sys
import subprocess
import shlex
import json
import glob
from pathlib import Path
IS_ROOT = (os.geteuid() == 0) if hasattr(os, "geteuid") else False
def run(cmd, env=None, check=True):
print(f"\n>>> {cmd}")
result = subprocess.run(shlex.split(cmd), env=env, stdout=sys.stdout, stderr=sys.stderr)
if check and result.returncode != 0:
print(f"[ERROR] Command failed: {cmd}")
sys.exit(result.returncode)
return result.returncode
def py_run(code, check=True):
print(f"\n>>> python - <<'PY' ...")
p = subprocess.Popen([sys.executable, "-c", code])
p.wait()
if check and p.returncode != 0:
print("[ERROR] Inline python failed.")
sys.exit(p.returncode)
return p.returncode
def detect_torch():
code = r"""
import json, sys
try:
import torch
info = {
"torch_version": torch.__version__,
"cuda_runtime": getattr(torch.version, "cuda", None),
"cuda_available": torch.cuda.is_available(),
"device_capability": None,
"device_name": None,
}
if info["cuda_available"]:
info["device_name"] = torch.cuda.get_device_name(0)
info["device_capability"] = torch.cuda.get_device_capability(0)
print(json.dumps(info))
except Exception as e:
print(json.dumps({"error": str(e)}))
"""
out = subprocess.check_output([sys.executable, "-c", code], text=True)
return json.loads(out.strip())
def set_cuda_env(cuda_home_guess=None):
# best-effort set CUDA paths
candidates = []
if cuda_home_guess:
candidates.append(cuda_home_guess)
candidates += [
"/usr/local/cuda",
"/usr/local/cuda-12.5", "/usr/local/cuda-12.4", "/usr/local/cuda-12.3",
"/usr/local/cuda-12.2", "/usr/local/cuda-12.1", "/usr/local/cuda-12.0",
"/usr/local/cuda-11.8", "/usr/local/cuda-11.7",
]
for c in candidates:
if Path(c).exists():
os.environ["CUDA_HOME"] = c
os.environ["PATH"] = f"{c}/bin:" + os.environ.get("PATH", "")
os.environ["LD_LIBRARY_PATH"] = f"{c}/lib64:" + os.environ.get("LD_LIBRARY_PATH", "")
print(f"[INFO] Using CUDA at {c}")
return
print("[WARN] CUDA not found on typical paths; proceeding anyway.")
def apt_install(packages):
if not IS_ROOT:
print("[WARN] Skipping apt-get because this process is not root.")
return
run("apt-get update")
run(f"apt-get install -y {' '.join(packages)}")
def pip_install(pkgs, flags=""):
run(f"{sys.executable} -m pip install -U {flags} {' '.join(pkgs)}")
def remove_old_igl():
# pip uninstall
run(f"{sys.executable} -m pip uninstall -y igl || true", check=False)
# hard cleanup
code = r"""
import sys, os, glob, shutil
removed = []
for sp in sys.path:
for pat in ("igl", "igl-*"):
for p in glob.glob(os.path.join(sp, pat)):
try:
if os.path.isdir(p):
shutil.rmtree(p, ignore_errors=True)
else:
os.remove(p)
removed.append(p)
except Exception: pass
print("\n".join(removed))
"""
print("[INFO] Removing leftover igl files (if any):")
py_run(code, check=False)
def build_libigl(src_dir="/Isotropic3D/libigl-python-bindings"):
# clone if needed
if not Path(src_dir).exists():
run(f"git clone --recursive https://github.com/libigl/libigl-python-bindings.git {src_dir}")
else:
run(f"git -C {src_dir} submodule update --init --recursive")
# install with no build isolation so it sees our env
run(f"{sys.executable} -m pip install -v --no-build-isolation .", env=os.environ | {}, check=True)
def verify_igl():
code = r"""
import igl
print("igl module path:", igl.__file__)
print("has fast_winding_number_for_meshes:", hasattr(igl, "fast_winding_number_for_meshes"))
"""
py_run(code)
def compute_arch_from_capability(cap=None):
# map major.minor to CMake arch (rounded typical)
# Lovelace(8.9)=89, Ampere(8.6)=86, A100(8.0)=80, Turing(7.5)=75, Volta(7.0)=70
mapping = {(8,9): 89, (8,6): 86, (8,0): 80, (7,5): 75, (7,0): 70}
if isinstance(cap, (list, tuple)) and len(cap) >= 2:
return mapping.get((cap[0], cap[1]), cap[0]*10 + cap[1])
return None
def ensure_tinycudann(src_dir="/Isotropic3D/tiny-cuda-nn", arch=None):
# uninstall old
run(f"{sys.executable} -m pip uninstall -y tinycudann tiny-cuda-nn || true", check=False)
# clone if needed
if not Path(src_dir).exists():
run(f"git clone --recursive https://github.com/NVlabs/tiny-cuda-nn.git {src_dir}")
else:
run(f"git -C {src_dir} submodule update --init --recursive")
bind_dir = Path(src_dir) / "bindings" / "torch"
if not bind_dir.exists():
print("[ERROR] tiny-cuda-nn bindings/torch not found.")
sys.exit(2)
env = os.environ.copy()
if arch:
env["TCNN_CUDA_ARCHITECTURES"] = str(arch)
env["TORCH_CUDA_LIST"] = "" # avoid confusion
# Build with no build isolation so it can use our Torch/pybind11
run(f"{sys.executable} -m pip install -v --no-build-isolation .", env=env | {}, check=True)
def verify_tcnn():
code = r"""
import torch
import tinycudann as tcnn
print("tinycudann import OK; torch", torch.__version__)
"""
py_run(code)
def main():
import argparse
ap = argparse.ArgumentParser(description="Fix igl and (optional) tinycudann for Isotropic3D.")
ap.add_argument("--cuda-home", type=str, default=None, help="Custom CUDA_HOME path (optional).")
ap.add_argument("--do-tcnn", action="store_true", help="Also build tiny-cuda-nn bindings.")
ap.add_argument("--libigl-src", type=str, default="/Isotropic3D/libigl-python-bindings")
ap.add_argument("--tcnn-src", type=str, default="/Isotropic3D/tiny-cuda-nn")
args = ap.parse_args()
# 0) Toolchain + backend
apt_install(["build-essential", "cmake", "ninja-build", "git", "libeigen3-dev"])
pip_install(["pip", "wheel", "setuptools", "scikit-build-core", "pybind11", "numpy"])
# 1) CUDA env (best effort)
set_cuda_env(args.cuda_home)
# 2) Reinstall igl properly
print("\n=== Reinstalling libigl (igl) ===")
remove_old_igl()
# Install from local clone or clone to default dir then install
if Path(args.libigl_src).exists():
run(f"git -C {args.libigl_src} submodule update --init --recursive")
run(f"{sys.executable} -m pip install -v --no-build-isolation .", env=os.environ | {}, check=True)
else:
build_libigl(args.libigl_src)
print("\n=== Verifying igl ===")
verify_igl()
# 3) (Optional) Build tinycudann
if args.do_tcnn:
print("\n=== Building tiny-cuda-nn / tinycudann ===")
info = detect_torch()
print(f"[INFO] Torch info: {info}")
arch = None
if info.get("cuda_available") and info.get("device_capability"):
arch = compute_arch_from_capability(info["device_capability"])
print(f"[INFO] Detected GPU capability {info['device_capability']} -> arch {arch}")
else:
print("[WARN] CUDA not available from torch; proceeding without arch hint.")
ensure_tinycudann(args.tcnn_src, arch=arch)
print("\n=== Verifying tinycudann ===")
verify_tcnn()
print("\n[OK] All done. You can now run Isotropic3D:")
print(" cd /Isotropic3D")
print(" python launch.py --config configs/isotropic3d-shading.yaml --train --gpu 0")
if __name__ == "__main__":
main()