Module: Ignis::Platform
- Defined in:
- lib/nnw/platform.rb
Overview
Cross-platform detection and path resolution for Ignis.
Windows is the primary target (the whole point — Ruby HPC without Python’s 20-30% overhead). Linux support exists for multi-GPU bare-metal testing on Lambda / RunPod / Azure instances.
Usage:
Ignis::Platform.windows? # => true on dev box
Ignis::Platform.cuda_lib('cudart') # => 'cudart64_130.dll' or 'libcudart.so.13'
Ignis::Platform.cuda_bin_path # => 'C:/Program Files/.../bin' or '/usr/local/cuda/lib64'
Constant Summary collapse
- CUDA_VERSION_MAJOR =
CUDA Paths
13- CUDA_VERSION_MINOR =
0- WIN_CUDA_ROOT =
Windows CUDA root
File.join('C:', 'Program Files', 'NVIDIA GPU Computing Toolkit', 'CUDA', "v#{CUDA_VERSION_MAJOR}.#{CUDA_VERSION_MINOR}").freeze
- WIN_CUDA_BIN =
File.join(WIN_CUDA_ROOT, 'bin').freeze
- LINUX_CUDA_ROOT =
Linux CUDA root (standard install or Lambda Stack)
"/usr/local/cuda-#{CUDA_VERSION_MAJOR}.#{CUDA_VERSION_MINOR}".freeze
- LINUX_CUDA_LIB =
File.join(LINUX_CUDA_ROOT, 'lib64').freeze
- LINUX_CUDA_ALT =
'/usr/local/cuda'.freeze
- LINUX_CUDA_ALT_LIB =
File.join(LINUX_CUDA_ALT, 'lib64').freeze
- WIN_DLL_SUBDIRS =
Candidate sub-directories that hold the CUDA redistributable DLLs under a toolkit root. CUDA 13 on Windows moved them from bin\ to binx64, so both must be probed.
[File.join('bin', 'x64'), 'bin'].freeze
- WIN_LIB_PATTERNS =
Windows DLL patterns
{ cuda_runtime: 'cudart64_*.dll', cublas: 'cublas64_*.dll', cublaslt: 'cublasLt64_*.dll', cufft: 'cufft64_*.dll', curand: 'curand64_*.dll', cusparse: 'cusparse64_*.dll', cusolver: 'cusolver64_*.dll', cudnn: 'cudnn64_*.dll', nvrtc: 'nvrtc64_*.dll', cutensor: 'cutensor.dll', cudss: 'cudss64_*.dll', mathdx: 'mathdx64_0.dll', cuda_driver: 'nvcuda.dll' }.freeze
- LINUX_LIB_PATTERNS =
Linux .so patterns
{ cuda_runtime: 'libcudart.so*', cublas: 'libcublas.so*', cublaslt: 'libcublasLt.so*', cufft: 'libcufft.so*', curand: 'libcurand.so*', cusparse: 'libcusparse.so*', cusolver: 'libcusolver.so*', cudnn: 'libcudnn.so*', nvrtc: 'libnvrtc.so*', cutensor: 'libcutensor.so*', cudss: 'libcudss.so*', mathdx: 'libmathdx.so*', cuda_driver: 'libcuda.so*' }.freeze
Class Method Summary collapse
-
.cuda_bin_path ⇒ String
CUDA binary/library directory for the current OS.
-
.cuda_lib_pattern(key) ⇒ String
Maps library keys to their platform-specific filenames.
-
.cuda_root ⇒ String
CUDA root directory.
-
.cudart_path ⇒ String
Resolve the CUDA runtime library path directly.
-
.custom_lib_paths ⇒ Hash{Symbol => String}
Custom search paths per library.
-
.find_cuda_lib(key) ⇒ String?
Resolve the full path to a specific CUDA library.
-
.info ⇒ Hash
Platform summary for debugging.
-
.kernel32_available? ⇒ Boolean
True if Kernel32 (Windows DLL path management) is available.
-
.linux? ⇒ Boolean
True if running on Linux.
-
.macos? ⇒ Boolean
True if running on macOS (unlikely for GPU work).
-
.os ⇒ Symbol
:windows, :linux, or :macos.
-
.path_separator ⇒ String
Path separator for the OS.
-
.shared_lib_ext ⇒ String
Shared library extension.
-
.win_cuda_bin ⇒ String
Resolve the directory that actually contains the CUDA redistributable DLLs (binx64 on CUDA 13, bin on older layouts).
-
.win_cuda_root ⇒ String
Discover the installed Windows CUDA toolkit root.
-
.windows? ⇒ Boolean
True if running on Windows.
-
.wnais_native_lib ⇒ String
Expected path to WNAIS native AOT binary.
Class Method Details
.cuda_bin_path ⇒ String
Returns CUDA binary/library directory for the current OS.
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/nnw/platform.rb', line 108 def self.cuda_bin_path if windows? win_cuda_bin else # Prefer versioned path, fall back to symlinked /usr/local/cuda if Dir.exist?(LINUX_CUDA_LIB) LINUX_CUDA_LIB elsif Dir.exist?(LINUX_CUDA_ALT_LIB) LINUX_CUDA_ALT_LIB else # Lambda Stack / system CUDA — libraries on LD_LIBRARY_PATH '/usr/lib/x86_64-linux-gnu' end end end |
.cuda_lib_pattern(key) ⇒ String
Maps library keys to their platform-specific filenames. Windows uses DLLs, Linux uses shared objects.
142 143 144 145 146 147 148 |
# File 'lib/nnw/platform.rb', line 142 def self.cuda_lib_pattern(key) if windows? WIN_LIB_PATTERNS[key] || raise(ArgumentError, "Unknown CUDA library: #{key}") else LINUX_LIB_PATTERNS[key] || raise(ArgumentError, "Unknown CUDA library: #{key}") end end |
.cuda_root ⇒ String
Returns CUDA root directory.
125 126 127 128 129 130 131 |
# File 'lib/nnw/platform.rb', line 125 def self.cuda_root if windows? win_cuda_root else Dir.exist?(LINUX_CUDA_ROOT) ? LINUX_CUDA_ROOT : LINUX_CUDA_ALT end end |
.cudart_path ⇒ String
Resolve the CUDA runtime library path directly.
167 168 169 170 171 172 173 174 175 |
# File 'lib/nnw/platform.rb', line 167 def self.cudart_path if windows? found = find_cuda_lib(:cuda_runtime) found || File.join(WIN_CUDA_BIN, "cudart64_#{CUDA_VERSION_MAJOR}0.dll") else found = find_cuda_lib(:cuda_runtime) found || "libcudart.so.#{CUDA_VERSION_MAJOR}" end end |
.custom_lib_paths ⇒ Hash{Symbol => String}
Returns custom search paths per library.
192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/nnw/platform.rb', line 192 def self.custom_lib_paths if windows? { cutensor: 'C:/Program Files/NVIDIA cuTENSOR/v2.4/bin/13', cudss: 'C:/Program Files/NVIDIA cuDSS/v0.7/bin/13' } else { cutensor: '/usr/local/cutensor/lib', cudss: '/usr/local/cudss/lib' } end end |
.find_cuda_lib(key) ⇒ String?
Resolve the full path to a specific CUDA library.
153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/nnw/platform.rb', line 153 def self.find_cuda_lib(key) pattern = cuda_lib_pattern(key) search_paths = cuda_search_paths(key) search_paths.each do |dir| matches = Dir.glob(File.join(dir, pattern)) return matches.max if matches.any? end nil end |
.info ⇒ Hash
Returns platform summary for debugging.
233 234 235 236 237 238 239 240 241 242 243 244 |
# File 'lib/nnw/platform.rb', line 233 def self.info { os: os, ruby_platform: RUBY_PLATFORM, cuda_version: "#{CUDA_VERSION_MAJOR}.#{CUDA_VERSION_MINOR}", cuda_root: cuda_root, cuda_bin: cuda_bin_path, cudart: cudart_path, kernel32: kernel32_available?, shared_lib_ext: shared_lib_ext } end |
.kernel32_available? ⇒ Boolean
Returns true if Kernel32 (Windows DLL path management) is available.
211 212 213 |
# File 'lib/nnw/platform.rb', line 211 def self.kernel32_available? windows? end |
.linux? ⇒ Boolean
Returns true if running on Linux.
25 26 27 |
# File 'lib/nnw/platform.rb', line 25 def self.linux? RUBY_PLATFORM.match?(/linux/i) end |
.macos? ⇒ Boolean
Returns true if running on macOS (unlikely for GPU work).
30 31 32 |
# File 'lib/nnw/platform.rb', line 30 def self.macos? RUBY_PLATFORM.match?(/darwin/i) end |
.os ⇒ Symbol
Returns :windows, :linux, or :macos.
35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/nnw/platform.rb', line 35 def self.os if windows? :windows elsif linux? :linux elsif macos? :macos else :unknown end end |
.path_separator ⇒ String
Returns path separator for the OS.
178 179 180 |
# File 'lib/nnw/platform.rb', line 178 def self.path_separator windows? ? ';' : ':' end |
.shared_lib_ext ⇒ String
Returns shared library extension.
183 184 185 |
# File 'lib/nnw/platform.rb', line 183 def self.shared_lib_ext windows? ? '.dll' : '.so' end |
.win_cuda_bin ⇒ String
Resolve the directory that actually contains the CUDA redistributable DLLs (binx64 on CUDA 13, bin on older layouts). Memoized.
99 100 101 102 103 104 105 |
# File 'lib/nnw/platform.rb', line 99 def self.win_cuda_bin @win_cuda_bin ||= begin root = win_cuda_root sub = WIN_DLL_SUBDIRS.find { |s| Dir.glob(File.join(root, s, 'cudart64_*.dll')).any? } File.join(root, sub || 'bin') end end |
.win_cuda_root ⇒ String
Discover the installed Windows CUDA toolkit root.
The compiled-in v#MAJOR.#MINOR default is only a last resort: real installs vary (v13.0 / v13.1 / v13.2 / …). We prefer the CUDA_PATH env var set by the NVIDIA installer, then the highest-versioned vX.Y directory that actually contains a CUDA runtime DLL. Memoized.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/nnw/platform.rb', line 76 def self.win_cuda_root @win_cuda_root ||= begin candidates = [] env_root = ENV['CUDA_PATH'] candidates << env_root if env_root && !env_root.empty? base = File.join('C:', 'Program Files', 'NVIDIA GPU Computing Toolkit', 'CUDA') versioned = Dir.glob(File.join(base, 'v*')).select { |d| File.directory?(d) } versioned = versioned.sort_by do |d| (m = d.match(/v(\d+)\.(\d+)/)) ? [m[1].to_i, m[2].to_i] : [0, 0] end.reverse # highest version first (v13.2 before v13.0) candidates.concat(versioned) chosen = candidates.find do |root| WIN_DLL_SUBDIRS.any? { |sub| Dir.glob(File.join(root, sub, 'cudart64_*.dll')).any? } end chosen || WIN_CUDA_ROOT end end |
.windows? ⇒ Boolean
Returns true if running on Windows.
20 21 22 |
# File 'lib/nnw/platform.rb', line 20 def self.windows? RUBY_PLATFORM.match?(/mswin|mingw|cygwin/i) || (defined?(FFI) && FFI::Platform::IS_WINDOWS) end |
.wnais_native_lib ⇒ String
Returns expected path to WNAIS native AOT binary.
220 221 222 223 224 225 226 |
# File 'lib/nnw/platform.rb', line 220 def self.wnais_native_lib if windows? 'Wnais.Core.dll' else 'Wnais.Core.so' end end |