// // Copyright 2020-2024 Picovoice Inc. // // You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE" // file accompanying this source. // // Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on // an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. // 'use strict'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import { RhinoRuntimeError } from './errors'; const SYSTEM_LINUX = 'linux'; const SYSTEM_MAC = 'darwin'; const SYSTEM_WINDOWS = 'win32'; const X86_64 = 'x64'; const ARM_32 = 'arm'; const ARM_64 = 'arm64'; const PLATFORM_LINUX = 'linux'; const PLATFORM_MAC = 'mac'; const PLATFORM_RASPBERRY_PI = 'raspberry-pi'; const PLATFORM_WINDOWS = 'windows'; const ARM_CPU_64 = '-aarch64'; const ARM_CPU_CORTEX_A53 = 'cortex-a53'; const ARM_CPU_CORTEX_A72 = 'cortex-a72'; const ARM_CPU_CORTEX_A76 = 'cortex-a76'; const SUPPORTED_NODEJS_SYSTEMS = new Set([ SYSTEM_LINUX, SYSTEM_MAC, SYSTEM_WINDOWS, ]); const LIBRARY_PATH_PREFIX = '../lib/'; const SYSTEM_TO_LIBRARY_PATH = new Map(); SYSTEM_TO_LIBRARY_PATH.set( `${SYSTEM_MAC}/${X86_64}`, `${PLATFORM_MAC}/x86_64/pv_rhino.node` ); SYSTEM_TO_LIBRARY_PATH.set( `${SYSTEM_MAC}/${ARM_64}`, `${PLATFORM_MAC}/arm64/pv_rhino.node` ); SYSTEM_TO_LIBRARY_PATH.set( `${SYSTEM_LINUX}/${X86_64}`, `${PLATFORM_LINUX}/x86_64/pv_rhino.node` ); SYSTEM_TO_LIBRARY_PATH.set( `${SYSTEM_LINUX}/${ARM_CPU_CORTEX_A53}`, `${PLATFORM_RASPBERRY_PI}/${ARM_CPU_CORTEX_A53}/pv_rhino.node` ); SYSTEM_TO_LIBRARY_PATH.set( `${SYSTEM_LINUX}/${ARM_CPU_CORTEX_A53}${ARM_CPU_64}`, `${PLATFORM_RASPBERRY_PI}/${ARM_CPU_CORTEX_A53}${ARM_CPU_64}/pv_rhino.node` ); SYSTEM_TO_LIBRARY_PATH.set( `${SYSTEM_LINUX}/${ARM_CPU_CORTEX_A72}`, `${PLATFORM_RASPBERRY_PI}/${ARM_CPU_CORTEX_A72}/pv_rhino.node` ); SYSTEM_TO_LIBRARY_PATH.set( `${SYSTEM_LINUX}/${ARM_CPU_CORTEX_A72}${ARM_CPU_64}`, `${PLATFORM_RASPBERRY_PI}/${ARM_CPU_CORTEX_A72}${ARM_CPU_64}/pv_rhino.node` ); SYSTEM_TO_LIBRARY_PATH.set( `${SYSTEM_LINUX}/${ARM_CPU_CORTEX_A76}`, `${PLATFORM_RASPBERRY_PI}/${ARM_CPU_CORTEX_A76}/pv_rhino.node` ); SYSTEM_TO_LIBRARY_PATH.set( `${SYSTEM_LINUX}/${ARM_CPU_CORTEX_A76}${ARM_CPU_64}`, `${PLATFORM_RASPBERRY_PI}/${ARM_CPU_CORTEX_A76}${ARM_CPU_64}/pv_rhino.node` ); SYSTEM_TO_LIBRARY_PATH.set( `${SYSTEM_WINDOWS}/${X86_64}`, `${PLATFORM_WINDOWS}/amd64/pv_rhino.node` ); SYSTEM_TO_LIBRARY_PATH.set( `${SYSTEM_WINDOWS}/${ARM_64}`, `${PLATFORM_WINDOWS}/arm64/pv_rhino.node` ); function absoluteLibraryPath(libraryPath: string): string { return path.resolve(__dirname, LIBRARY_PATH_PREFIX, libraryPath); } function getCpuPart(): string { const cpuInfo = fs.readFileSync('/proc/cpuinfo', 'ascii'); for (const infoLine of cpuInfo.split('\n')) { if (infoLine.includes('CPU part')) { const infoLineSplit = infoLine.split(' '); return infoLineSplit[infoLineSplit.length - 1].toLowerCase(); } } throw new RhinoRuntimeError(`Unsupported CPU.`); } function getLinuxPlatform(): string { const cpuPart = getCpuPart(); switch (cpuPart) { case '0xd03': case '0xd08': case '0xd0b': return PLATFORM_RASPBERRY_PI; default: throw new RhinoRuntimeError(`Unsupported CPU: '${cpuPart}'`); } } function getLinuxMachine(arch: string): string { let archInfo = ''; if (arch === ARM_64) { archInfo = ARM_CPU_64; } const cpuPart = getCpuPart(); switch (cpuPart) { case '0xd03': return ARM_CPU_CORTEX_A53 + archInfo; case '0xd08': return ARM_CPU_CORTEX_A72 + archInfo; case '0xd0b': return ARM_CPU_CORTEX_A76 + archInfo; default: throw new RhinoRuntimeError(`Unsupported CPU: '${cpuPart}'`); } } export function getPlatform(): string { const system = os.platform(); const arch = os.arch(); if (system === SYSTEM_MAC && (arch === X86_64 || arch === ARM_64)) { return PLATFORM_MAC; } if (system === SYSTEM_WINDOWS && (arch === X86_64 || arch === ARM_64)) { return PLATFORM_WINDOWS; } if (system === SYSTEM_LINUX) { if (arch === X86_64) { return PLATFORM_LINUX; } return getLinuxPlatform(); } throw `System ${system}/${arch} is not supported by this library.`; } export function getSystemLibraryPath(): string { const system = os.platform(); const arch = os.arch(); if (SUPPORTED_NODEJS_SYSTEMS.has(system)) { switch (system) { case SYSTEM_MAC: { if (arch === X86_64) { return absoluteLibraryPath( SYSTEM_TO_LIBRARY_PATH.get(`${SYSTEM_MAC}/${X86_64}`) ); } else if (arch === ARM_64) { return absoluteLibraryPath( SYSTEM_TO_LIBRARY_PATH.get(`${SYSTEM_MAC}/${ARM_64}`) ); } break; } case SYSTEM_LINUX: { if (arch === X86_64) { return absoluteLibraryPath( SYSTEM_TO_LIBRARY_PATH.get(`${SYSTEM_LINUX}/${X86_64}`) ); } else if (arch === ARM_32 || arch === ARM_64) { const linuxMachine = getLinuxMachine(arch); if (linuxMachine !== null) { return absoluteLibraryPath( SYSTEM_TO_LIBRARY_PATH.get(`${SYSTEM_LINUX}/${linuxMachine}`) ); } throw new RhinoRuntimeError( `System ${system}/${arch} is not supported by this library for this CPU.` ); } break; } case SYSTEM_WINDOWS: { if (arch === X86_64 || arch === ARM_64) { return absoluteLibraryPath( SYSTEM_TO_LIBRARY_PATH.get(`${SYSTEM_WINDOWS}/${arch}`) ); } break; } default: { throw new RhinoRuntimeError( `System ${system}/${arch} is not supported by this library.` ); } } } throw new RhinoRuntimeError( `System ${system}/${arch} is not supported by this library.` ); }