| |
| |
| |
|
|
| 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): |
| |
| 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(): |
| |
| run(f"{sys.executable} -m pip uninstall -y igl || true", check=False) |
| |
| 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"): |
| |
| 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") |
|
|
| |
| 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): |
| |
| |
| 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): |
| |
| run(f"{sys.executable} -m pip uninstall -y tinycudann tiny-cuda-nn || true", check=False) |
|
|
| |
| 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"] = "" |
| |
| 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() |
|
|
| |
| apt_install(["build-essential", "cmake", "ninja-build", "git", "libeigen3-dev"]) |
| pip_install(["pip", "wheel", "setuptools", "scikit-build-core", "pybind11", "numpy"]) |
|
|
| |
| set_cuda_env(args.cuda_home) |
|
|
| |
| print("\n=== Reinstalling libigl (igl) ===") |
| remove_old_igl() |
| |
| 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() |
|
|
| |
| 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() |
|
|