Files
leon-ai--leon/scripts/setup/setup-nvidia-libs.js
T
2026-07-13 12:44:08 +08:00

359 lines
11 KiB
JavaScript

import fs from 'node:fs'
import path from 'node:path'
import {
NVIDIA_LIBS_PATH,
NVIDIA_CUBLAS_PATH,
NVIDIA_CUDNN_PATH,
NVIDIA_CUDA_CUDART_PATH,
NVIDIA_CUDA_CUPTI_PATH,
NVIDIA_CUSPARSE_PATH,
NVIDIA_CUSPARSELT_PATH,
NVIDIA_CUSPARSE_FULL_PATH,
NVIDIA_NCCL_PATH,
NVIDIA_NVSHMEM_PATH,
NVIDIA_NVJITLINK_PATH,
NVIDIA_CUBLAS_MANIFEST_PATH,
NVIDIA_CUDNN_MANIFEST_PATH,
NVIDIA_CUDA_CUDART_MANIFEST_PATH,
NVIDIA_CUDA_CUPTI_MANIFEST_PATH,
NVIDIA_CUSPARSE_MANIFEST_PATH,
NVIDIA_CUSPARSE_FULL_MANIFEST_PATH,
NVIDIA_NCCL_MANIFEST_PATH,
NVIDIA_NVSHMEM_MANIFEST_PATH,
NVIDIA_NVJITLINK_MANIFEST_PATH,
NVIDIA_CUDA_VERSION,
NVIDIA_CUBLAS_VERSION,
NVIDIA_CUDNN_VERSION,
NVIDIA_CUDA_CUDART_VERSION,
NVIDIA_CUDA_CUPTI_VERSION,
NVIDIA_CUSPARSE_VERSION,
NVIDIA_CUSPARSE_FULL_VERSION,
NVIDIA_NCCL_VERSION,
NVIDIA_NVSHMEM_VERSION,
NVIDIA_NVJITLINK_VERSION,
PYTORCH_NVIDIA_PATH,
PYTORCH_TORCH_PATH
} from '@/constants'
import { FileHelper } from '@/helpers/file-helper'
import { SystemHelper } from '@/helpers/system-helper'
import { createSetupStatus } from './setup-status'
const { type: OS_TYPE, cpuArchitecture: CPU_ARCH } =
SystemHelper.getInformation()
const NVIDIA_LIBRARY_LABELS = {
cublas: 'cuBLAS',
cudnn: 'cuDNN',
cuda_cudart: 'CUDA Runtime',
cuda_cupti: 'CUDA CUPTI',
cusparse: 'cuSPARSE Lt',
cusparse_full: 'cuSPARSE',
nccl: 'NCCL',
nvshmem: 'NVSHMEM',
nvjitlink: 'nvJitLink'
}
/**
* Map CPU architecture to NVIDIA's architecture naming convention
*/
function mapToNvidiaArch(cpuArch) {
// Map Node.js process.arch values to NVIDIA naming
if (cpuArch === 'arm64' || cpuArch === 'aarch64') {
return 'aarch64'
}
if (cpuArch === 'x64' || cpuArch === 'x86_64') {
return 'x86_64'
}
return 'x86_64'
}
async function ensureDirectoryLink(linkPath, targetPath) {
if (!fs.existsSync(targetPath)) {
return
}
await fs.promises.rm(linkPath, { recursive: true, force: true })
await fs.promises.mkdir(path.dirname(linkPath), { recursive: true })
const relativeTarget = path.relative(path.dirname(linkPath), targetPath)
const linkType = SystemHelper.isWindows() ? 'junction' : 'dir'
await fs.promises.symlink(relativeTarget, linkPath, linkType)
}
async function ensureCompatibilityLinks() {
await ensureDirectoryLink(NVIDIA_CUSPARSELT_PATH, NVIDIA_CUSPARSE_PATH)
await ensureDirectoryLink(
path.join(NVIDIA_LIBS_PATH, 'cuda_runtime'),
NVIDIA_CUDA_CUDART_PATH
)
if (fs.existsSync(PYTORCH_TORCH_PATH)) {
await ensureDirectoryLink(PYTORCH_NVIDIA_PATH, NVIDIA_LIBS_PATH)
}
}
/**
* Read manifest file to get installed version
*/
function readManifest(manifestPath) {
if (!fs.existsSync(manifestPath)) {
return null
}
try {
const content = fs.readFileSync(manifestPath, 'utf-8')
return JSON.parse(content)
} catch {
return null
}
}
/**
* Get download URL for NVIDIA libraries
*/
function getNVIDIADownloadURL(library, version) {
const ext = SystemHelper.isWindows() ? 'zip' : 'tar.xz'
const arch = mapToNvidiaArch(CPU_ARCH)
// NVIDIA CDN URLs for CUDA libraries and more
if (library === 'cublas') {
return `https://developer.download.nvidia.com/compute/cuda/redist/libcublas/${OS_TYPE}-${arch}/libcublas-${OS_TYPE}-${arch}-${version}-archive.${ext}`
} else if (library === 'cudnn') {
return `https://developer.download.nvidia.com/compute/cudnn/redist/cudnn/${OS_TYPE}-${arch}/cudnn-${OS_TYPE}-${arch}-${version}_cuda${NVIDIA_CUDA_VERSION}-archive.${ext}`
} else if (library === 'cuda_cudart') {
return `https://developer.download.nvidia.com/compute/cuda/redist/cuda_cudart/${OS_TYPE}-${arch}/cuda_cudart-${OS_TYPE}-${arch}-${version}-archive.${ext}`
} else if (library === 'cuda_cupti') {
return `https://developer.download.nvidia.com/compute/cuda/redist/cuda_cupti/${OS_TYPE}-${arch}/cuda_cupti-${OS_TYPE}-${arch}-${version}-archive.${ext}`
} else if (library === 'cusparse') {
return `https://developer.download.nvidia.com/compute/cusparselt/redist/libcusparse_lt/${OS_TYPE}-${arch}/libcusparse_lt-${OS_TYPE}-${arch}-${version}_cuda${NVIDIA_CUDA_VERSION}-archive.${ext}`
} else if (library === 'cusparse_full') {
return `https://developer.download.nvidia.com/compute/cuda/redist/libcusparse/${OS_TYPE}-${arch}/libcusparse-${OS_TYPE}-${arch}-${version}-archive.${ext}`
} else if (library === 'nccl') {
// NCCL is only available on Linux x86_64
if (!SystemHelper.isLinux() || arch !== 'x86_64') {
throw new Error('NCCL is only available on Linux x86_64')
}
return `https://developer.download.nvidia.com/compute/nccl/redist/nccl/${OS_TYPE}-${arch}/nccl-${OS_TYPE}-${arch}-${version}-archive.${ext}`
} else if (library === 'nvshmem') {
// NVSHMEM is only available on Linux x86_64
if (!SystemHelper.isLinux() || arch !== 'x86_64') {
throw new Error('NVSHMEM is only available on Linux x86_64')
}
return `https://developer.download.nvidia.com/compute/nvshmem/redist/libnvshmem/${OS_TYPE}-${arch}/libnvshmem-${OS_TYPE}-${arch}-${version}_cuda${NVIDIA_CUDA_VERSION}-archive.${ext}`
} else if (library === 'nvjitlink') {
return `https://developer.download.nvidia.com/compute/cuda/redist/libnvjitlink/${OS_TYPE}-${arch}/libnvjitlink-${OS_TYPE}-${arch}-${version}-archive.${ext}`
}
}
/**
* Install NVIDIA libraries if needed
*/
async function installNVIDIALibrary(
library,
requiredVersion,
targetPath,
manifestPath
) {
const libraryLabel = NVIDIA_LIBRARY_LABELS[library] || library
const status = createSetupStatus(`Setting up ${libraryLabel}...`).start()
const manifest = readManifest(manifestPath)
if (!manifest || manifest.version !== requiredVersion) {
const ext = SystemHelper.isWindows() ? 'zip' : 'tar.xz'
const archivePath = path.join(
NVIDIA_LIBS_PATH,
`${library}-${requiredVersion}.${ext}`
)
// Clean up old version
await fs.promises.rm(targetPath, { recursive: true, force: true })
await fs.promises.rm(archivePath, { force: true })
// Create target directory
await fs.promises.mkdir(targetPath, { recursive: true })
try {
const downloadURL = getNVIDIADownloadURL(library, requiredVersion)
status.pause()
await FileHelper.downloadFile(downloadURL, archivePath, {
cliProgress: true,
parallelStreams: 3,
skipExisting: false
})
status.text = `Installing ${libraryLabel}...`
status.start()
// Extract archive using unified method
await FileHelper.extractArchive(archivePath, targetPath, {
stripComponents: 1
})
// Clean up and create manifest
await Promise.all([
fs.promises.rm(archivePath, { force: true }),
FileHelper.createManifestFile(manifestPath, library, requiredVersion, {
os: SystemHelper.getInformation().type,
architecture: SystemHelper.getInformation().cpuArchitecture
})
])
status.succeed(`${libraryLabel} ${requiredVersion} ready`)
} catch (error) {
if (status.isSpinning) {
status.fail(`Failed to set up ${libraryLabel}`)
}
throw new Error(
`${libraryLabel} may require manual download from https://developer.nvidia.com/cuda-downloads: ${error}`
)
}
} else {
status.succeed(`${libraryLabel}: ${requiredVersion}`)
}
}
/**
* Main setup function
*/
async function setupNVIDIALibs() {
// Skip on macOS since there is no CUDA involved
if (SystemHelper.isMacOS()) {
return
}
const status = createSetupStatus('Checking CUDA runtime support...').start()
try {
const { getLlama, LlamaLogLevel } = await Function(
'return import("node-llama-cpp")'
)()
const llama = await getLlama({
logLevel: LlamaLogLevel.disabled
})
const hasGPU = await SystemHelper.hasGPU(llama)
if (!hasGPU) {
status.succeed('CUDA runtime: skipped')
return
}
status.succeed('CUDA runtime: detected')
// Install/update cuBLAS
await installNVIDIALibrary(
'cublas',
NVIDIA_CUBLAS_VERSION,
NVIDIA_CUBLAS_PATH,
NVIDIA_CUBLAS_MANIFEST_PATH
)
// Install/update cuDNN
await installNVIDIALibrary(
'cudnn',
NVIDIA_CUDNN_VERSION,
NVIDIA_CUDNN_PATH,
NVIDIA_CUDNN_MANIFEST_PATH
)
// Install/update CUDA cudart runtime
await installNVIDIALibrary(
'cuda_cudart',
NVIDIA_CUDA_CUDART_VERSION,
NVIDIA_CUDA_CUDART_PATH,
NVIDIA_CUDA_CUDART_MANIFEST_PATH
)
// Install/update CUDA CUPTI
await installNVIDIALibrary(
'cuda_cupti',
NVIDIA_CUDA_CUPTI_VERSION,
NVIDIA_CUDA_CUPTI_PATH,
NVIDIA_CUDA_CUPTI_MANIFEST_PATH
)
// Install/update cuSPARSE-Lt (Linux only, both x86_64 and aarch64)
if (SystemHelper.isLinux()) {
try {
await installNVIDIALibrary(
'cusparse',
NVIDIA_CUSPARSE_VERSION,
NVIDIA_CUSPARSE_PATH,
NVIDIA_CUSPARSE_MANIFEST_PATH
)
} catch (error) {
status.warn(`cuSPARSE Lt skipped: ${error.message}`)
}
}
// Install/update cuSPARSE (Linux only, both x86_64 and aarch64)
if (SystemHelper.isLinux()) {
try {
await installNVIDIALibrary(
'cusparse_full',
NVIDIA_CUSPARSE_FULL_VERSION,
NVIDIA_CUSPARSE_FULL_PATH,
NVIDIA_CUSPARSE_FULL_MANIFEST_PATH
)
} catch (error) {
status.warn(`cuSPARSE skipped: ${error.message}`)
}
}
// Install/update nvJitLink (Linux only)
if (SystemHelper.isLinux()) {
try {
await installNVIDIALibrary(
'nvjitlink',
NVIDIA_NVJITLINK_VERSION,
NVIDIA_NVJITLINK_PATH,
NVIDIA_NVJITLINK_MANIFEST_PATH
)
} catch (error) {
status.warn(`nvJitLink skipped: ${error.message}`)
}
}
// Install/update NCCL (Linux x86_64 only)
if (SystemHelper.isLinux() && mapToNvidiaArch(CPU_ARCH) === 'x86_64') {
try {
await installNVIDIALibrary(
'nccl',
NVIDIA_NCCL_VERSION,
NVIDIA_NCCL_PATH,
NVIDIA_NCCL_MANIFEST_PATH
)
} catch (error) {
status.warn(`NCCL skipped: ${error.message}`)
}
}
// Install/update NVSHMEM (Linux x86_64 only)
if (SystemHelper.isLinux() && mapToNvidiaArch(CPU_ARCH) === 'x86_64') {
try {
await installNVIDIALibrary(
'nvshmem',
NVIDIA_NVSHMEM_VERSION,
NVIDIA_NVSHMEM_PATH,
NVIDIA_NVSHMEM_MANIFEST_PATH
)
} catch (error) {
status.warn(`NVSHMEM skipped: ${error.message}`)
}
}
await ensureCompatibilityLinks()
} catch (error) {
if (status.isSpinning) {
status.fail('Failed to inspect CUDA runtime support')
}
throw error
}
}
export default setupNVIDIALibs