| """Make Windows able to find the CUDA / cuDNN DLLs that CTranslate2 needs. |
| |
| The single most common failure when running faster-whisper / WhisperX on Windows is: |
| |
| RuntimeError: Library cudnn_ops64_9.dll is not found ... |
| (or: Could not locate cudnn_ops_infer64_8.dll) |
| |
| It happens because CTranslate2 loads cuDNN/cuBLAS by name via the OS loader, but the |
| DLLs live inside pip wheels (``nvidia-cudnn-cu12`` / ``nvidia-cublas-cu12``) or inside |
| ``torch/lib`` (the cu128 wheel bundles them) β directories that are NOT on the default |
| DLL search path. |
| |
| Importing this module **first** β before importing ``ctranslate2``, ``faster_whisper`` |
| or ``whisperx`` β registers those directories with the OS loader using |
| ``os.add_dll_directory`` (and prepends them to PATH as a belt-and-suspenders fallback). |
| |
| Usage:: |
| |
| from app import _cuda_bootstrap # noqa: F401 (must come first) |
| from faster_whisper import WhisperModel # now finds cuDNN |
| |
| This is a no-op on non-Windows platforms. |
| """ |
| from __future__ import annotations |
|
|
| import importlib.util |
| import os |
| import sys |
|
|
| |
| |
| _NVIDIA_PKGS = ( |
| "nvidia.cuda_runtime", |
| "nvidia.cuda_nvrtc", |
| "nvidia.cublas", |
| "nvidia.cudnn", |
| ) |
|
|
|
|
| def _add_dll_dir(path: str) -> bool: |
| if not path or not os.path.isdir(path): |
| return False |
| try: |
| os.add_dll_directory(path) |
| except (OSError, AttributeError): |
| return False |
| |
| |
| if path not in os.environ.get("PATH", ""): |
| os.environ["PATH"] = path + os.pathsep + os.environ.get("PATH", "") |
| return True |
|
|
|
|
| def _candidate_dirs() -> list[str]: |
| dirs: list[str] = [] |
| for pkg in _NVIDIA_PKGS: |
| try: |
| spec = importlib.util.find_spec(pkg) |
| except (ImportError, ValueError, ModuleNotFoundError): |
| spec = None |
| if spec and spec.submodule_search_locations: |
| base = list(spec.submodule_search_locations)[0] |
| |
| dirs.append(os.path.join(base, "bin")) |
| dirs.append(os.path.join(base, "lib")) |
| |
| try: |
| import torch |
|
|
| dirs.append(os.path.join(os.path.dirname(torch.__file__), "lib")) |
| except Exception: |
| pass |
| return dirs |
|
|
|
|
| def setup_cuda_dll_path() -> list[str]: |
| """Register CUDA/cuDNN DLL directories with the Windows loader. Returns dirs added.""" |
| if sys.platform != "win32": |
| return [] |
| added: list[str] = [] |
| for d in _candidate_dirs(): |
| if _add_dll_dir(d): |
| added.append(d) |
| return added |
|
|
|
|
| |
| ADDED_DLL_DIRS = setup_cuda_dll_path() |
|
|