Spaces:
Running
Running
File size: 7,034 Bytes
94004a2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | #!/usr/bin/env python3
"""Post-install setup for platform-specific runtime dependencies.
1. **Windows: VC++ Redistributable** — PyTorch's native DLLs (c10.dll,
torch_cpu.dll, etc.) link against vcruntime140.dll and msvcp140.dll from
the Microsoft Visual C++ 2015-2022 Redistributable. Fresh Windows installs
(especially debloated/LTSC-style) don't ship it. We detect and auto-install
it silently before any `import torch` can fail.
2. **CUDA: cuDNN 8 compat** — Ensures cuDNN 8 libraries are available for
CTranslate2 (faster-whisper / WhisperX) alongside PyTorch 2.8+'s cuDNN 9.
Run automatically as part of `bun run setup:api` — no user action required.
Cross-platform:
- Linux: cuDNN 8 compat (.so.8 libs)
- Windows: VC++ Redistributable + cuDNN 8 compat (.dll libs)
- macOS: skipped (no CUDA)
"""
import os
import sys
import subprocess
import glob
if sys.platform == "win32" and hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8")
# ── Windows: VC++ Redistributable ─────────────────────────────────────────
def _ensure_vcredist_windows():
"""Check for and install the VC++ 2015-2022 Redistributable on Windows.
PyTorch's native libraries (c10.dll, torch_cpu.dll, etc.) are built with
MSVC and dynamically link against vcruntime140.dll + msvcp140.dll. These
ship with Visual Studio / Build Tools but are NOT part of Windows itself.
On a fresh or debloated install the very first `import torch` crashes with:
OSError: [WinError 126] The specified module could not be found.
Error loading ...\\torch\\lib\\c10.dll or one of its dependencies.
This function silently downloads and installs the official x64 redist
package from Microsoft if the runtime DLLs are missing.
"""
if sys.platform != "win32":
return
# Check if vcruntime140.dll is already loadable
import ctypes
try:
ctypes.WinDLL("vcruntime140.dll")
print("✓ VC++ Redistributable: already installed")
return
except OSError:
pass
print("⚙ VC++ Redistributable not found — installing (required for PyTorch)...")
import tempfile
import urllib.request
vc_url = "https://aka.ms/vs/17/release/vc_redist.x64.exe"
installer = os.path.join(tempfile.gettempdir(), "vc_redist.x64.exe")
try:
# Download
print(" Downloading VC++ Redistributable...")
urllib.request.urlretrieve(vc_url, installer)
# Silent install (/install /quiet /norestart)
print(" Installing silently...")
result = subprocess.run(
[installer, "/install", "/quiet", "/norestart"],
timeout=120,
capture_output=True,
)
# Verify it worked
try:
ctypes.WinDLL("vcruntime140.dll")
print("✓ VC++ Redistributable: installed successfully")
except OSError:
# Exit code 3010 = success but reboot required
if result.returncode == 3010:
print("✓ VC++ Redistributable: installed (reboot recommended)")
else:
print(f"⚠ VC++ Redistributable: install may have failed (exit code {result.returncode})")
print(" Manual install: https://aka.ms/vs/17/release/vc_redist.x64.exe")
except Exception as e:
print(f"⚠ VC++ Redistributable: auto-install failed: {e}")
print(" Manual install: https://aka.ms/vs/17/release/vc_redist.x64.exe")
finally:
# Clean up installer
try:
os.remove(installer)
except OSError:
pass
# ── cuDNN 8 compat ────────────────────────────────────────────────────────
def _find_compat_dir():
"""Return the cudnn8_compat target directory, auto-detecting venv layout."""
script_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.dirname(script_dir)
venv_dir = os.path.join(project_root, ".venv")
if not os.path.isdir(venv_dir):
return None
if sys.platform == "win32":
# Windows: .venv/Lib/site-packages/
sp = os.path.join(venv_dir, "Lib", "site-packages", "cudnn8_compat")
else:
# Linux: .venv/lib/pythonX.Y/site-packages/
pyver = f"python{sys.version_info.major}.{sys.version_info.minor}"
sp = os.path.join(venv_dir, "lib", pyver, "site-packages", "cudnn8_compat")
return sp
def _cudnn8_lib_dir(compat_dir):
"""Return the cuDNN lib subdirectory within the compat install."""
if sys.platform == "win32":
return os.path.join(compat_dir, "nvidia", "cudnn", "bin")
return os.path.join(compat_dir, "nvidia", "cudnn", "lib")
def _count_cudnn8_libs(lib_dir):
"""Count cuDNN 8 shared libraries in the given directory."""
if sys.platform == "win32":
return len(glob.glob(os.path.join(lib_dir, "cudnn*64_8.dll")))
return len(glob.glob(os.path.join(lib_dir, "libcudnn*.so.8")))
def main():
# ── Step 1: Windows VC++ Redistributable ──────────────────────────────
_ensure_vcredist_windows()
# macOS — no CUDA, nothing to do
if sys.platform == "darwin":
return
compat_dir = _find_compat_dir()
if compat_dir is None:
return
lib_dir = _cudnn8_lib_dir(compat_dir)
# Already installed?
if os.path.isdir(lib_dir):
n = _count_cudnn8_libs(lib_dir)
if n >= 5:
print(f"✓ cuDNN 8 compat: {n} libraries ready")
return
# Check if CUDA is available before installing GPU-only libs
try:
result = subprocess.run(
[sys.executable, "-c", "import torch; print(torch.cuda.is_available())"],
capture_output=True, text=True, timeout=30,
)
if result.stdout.strip() != "True":
print("✓ No CUDA — cuDNN 8 compat not needed")
return
except Exception:
pass # Can't detect CUDA — install anyway, it's harmless on CPU
print("⚙ Installing cuDNN 8 compatibility libraries for CTranslate2...")
try:
subprocess.run(
[
sys.executable, "-m", "pip", "install",
"--no-deps", "--target", compat_dir,
"nvidia-cudnn-cu12==8.9.7.29",
],
check=True,
capture_output=True,
text=True,
timeout=180,
)
n = _count_cudnn8_libs(lib_dir)
print(f"✓ cuDNN 8 installed: {n} libraries")
except subprocess.CalledProcessError as e:
print(f"⚠ cuDNN 8 install failed (transcription may not work on CUDA):")
print(f" {(e.stderr or '')[:300]}")
except Exception as e:
print(f"⚠ cuDNN 8 install skipped: {e}")
if __name__ == "__main__":
main()
|