llama-cpp-pro 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/CHANGELOG.md +295 -0
  2. package/LICENSE +21 -0
  3. package/LlamaCpp.podspec +33 -0
  4. package/LlamaCppCapacitor.podspec +33 -0
  5. package/Package.swift +29 -0
  6. package/README.md +93 -0
  7. package/android/build.gradle +88 -0
  8. package/android/src/main/AndroidManifest.xml +4 -0
  9. package/android/src/main/CMakeLists-arm64.txt +138 -0
  10. package/android/src/main/CMakeLists-x86_64.txt +141 -0
  11. package/android/src/main/CMakeLists.txt +138 -0
  12. package/android/src/main/java/ai/annadata/plugin/capacitor/LlamaCpp.java +1340 -0
  13. package/android/src/main/java/ai/annadata/plugin/capacitor/LlamaCppPlugin.java +814 -0
  14. package/android/src/main/java/ai/annadata/plugin/capacitor/ModelAdmissionController.java +214 -0
  15. package/android/src/main/jni-chat-session.cpp +261 -0
  16. package/android/src/main/jni-lora.cpp +197 -0
  17. package/android/src/main/jni-multimodal.cpp +167 -0
  18. package/android/src/main/jni-tts.cpp +290 -0
  19. package/android/src/main/jni-utils.h +148 -0
  20. package/android/src/main/jni.cpp +1808 -0
  21. package/android/src/main/jniLibs/arm64-v8a/libllama-cpp-arm64.so +0 -0
  22. package/android/src/main/res/.gitkeep +0 -0
  23. package/build-native.sh +280 -0
  24. package/cmake/desktop-metal-embed.cmake +30 -0
  25. package/cmake/desktop-sources.cmake +100 -0
  26. package/cmake/ggml-backends.cmake +44 -0
  27. package/cpp/LICENSE +21 -0
  28. package/cpp/README.md +15 -0
  29. package/cpp/anyascii.c +22223 -0
  30. package/cpp/anyascii.h +42 -0
  31. package/cpp/cap-completion.cpp +942 -0
  32. package/cpp/cap-completion.h +127 -0
  33. package/cpp/cap-embedding.cpp +193 -0
  34. package/cpp/cap-embedding.h +35 -0
  35. package/cpp/cap-ios-bridge.cpp +1810 -0
  36. package/cpp/cap-ios-bridge.h +61 -0
  37. package/cpp/cap-llama.cpp +412 -0
  38. package/cpp/cap-llama.h +161 -0
  39. package/cpp/cap-mtmd.hpp +602 -0
  40. package/cpp/cap-native-server.cpp +1095 -0
  41. package/cpp/cap-native-server.h +40 -0
  42. package/cpp/cap-tts.cpp +591 -0
  43. package/cpp/cap-tts.h +59 -0
  44. package/cpp/cap-wasm-fs.cpp +156 -0
  45. package/cpp/cap-wasm-jspi.cpp +19 -0
  46. package/cpp/cap-wasm-jspi.h +30 -0
  47. package/cpp/cap-wasm-vfs.cpp +22 -0
  48. package/cpp/chat-parser.cpp +393 -0
  49. package/cpp/chat-parser.h +120 -0
  50. package/cpp/chat.cpp +2315 -0
  51. package/cpp/chat.h +221 -0
  52. package/cpp/common.cpp +1664 -0
  53. package/cpp/common.h +744 -0
  54. package/cpp/ggml-alloc.c +1028 -0
  55. package/cpp/ggml-alloc.h +76 -0
  56. package/cpp/ggml-backend-impl.h +255 -0
  57. package/cpp/ggml-backend-reg.cpp +600 -0
  58. package/cpp/ggml-backend.cpp +2121 -0
  59. package/cpp/ggml-backend.h +354 -0
  60. package/cpp/ggml-common.h +1878 -0
  61. package/cpp/ggml-cpp.h +39 -0
  62. package/cpp/ggml-cpu/amx/amx.cpp +221 -0
  63. package/cpp/ggml-cpu/amx/amx.h +8 -0
  64. package/cpp/ggml-cpu/amx/common.h +91 -0
  65. package/cpp/ggml-cpu/amx/mmq.cpp +2512 -0
  66. package/cpp/ggml-cpu/amx/mmq.h +10 -0
  67. package/cpp/ggml-cpu/arch/arm/cpu-feats.cpp +94 -0
  68. package/cpp/ggml-cpu/arch/arm/quants.c +3650 -0
  69. package/cpp/ggml-cpu/arch/arm/repack.cpp +1891 -0
  70. package/cpp/ggml-cpu/arch/x86/cpu-feats.cpp +327 -0
  71. package/cpp/ggml-cpu/arch/x86/quants.c +3820 -0
  72. package/cpp/ggml-cpu/arch/x86/repack.cpp +6307 -0
  73. package/cpp/ggml-cpu/arch-fallback.h +215 -0
  74. package/cpp/ggml-cpu/binary-ops.cpp +158 -0
  75. package/cpp/ggml-cpu/binary-ops.h +16 -0
  76. package/cpp/ggml-cpu/common.h +73 -0
  77. package/cpp/ggml-cpu/ggml-cpu-impl.h +559 -0
  78. package/cpp/ggml-cpu/ggml-cpu.c +3578 -0
  79. package/cpp/ggml-cpu/ggml-cpu.cpp +672 -0
  80. package/cpp/ggml-cpu/ops.cpp +10587 -0
  81. package/cpp/ggml-cpu/ops.h +114 -0
  82. package/cpp/ggml-cpu/quants.c +1193 -0
  83. package/cpp/ggml-cpu/quants.h +97 -0
  84. package/cpp/ggml-cpu/repack.cpp +1982 -0
  85. package/cpp/ggml-cpu/repack.h +120 -0
  86. package/cpp/ggml-cpu/simd-mappings.h +1184 -0
  87. package/cpp/ggml-cpu/traits.cpp +36 -0
  88. package/cpp/ggml-cpu/traits.h +38 -0
  89. package/cpp/ggml-cpu/unary-ops.cpp +186 -0
  90. package/cpp/ggml-cpu/unary-ops.h +28 -0
  91. package/cpp/ggml-cpu/vec.cpp +348 -0
  92. package/cpp/ggml-cpu/vec.h +1121 -0
  93. package/cpp/ggml-cpu.h +145 -0
  94. package/cpp/ggml-impl.h +622 -0
  95. package/cpp/ggml-metal-impl.h +688 -0
  96. package/cpp/ggml-metal.h +66 -0
  97. package/cpp/ggml-metal.m +6833 -0
  98. package/cpp/ggml-metal.metal +10754 -0
  99. package/cpp/ggml-opt.cpp +1093 -0
  100. package/cpp/ggml-opt.h +256 -0
  101. package/cpp/ggml-quants.c +5324 -0
  102. package/cpp/ggml-quants.h +106 -0
  103. package/cpp/ggml-threading.cpp +12 -0
  104. package/cpp/ggml-threading.h +14 -0
  105. package/cpp/ggml.c +7108 -0
  106. package/cpp/ggml.h +2492 -0
  107. package/cpp/gguf.cpp +1358 -0
  108. package/cpp/gguf.h +202 -0
  109. package/cpp/json-partial.cpp +256 -0
  110. package/cpp/json-partial.h +38 -0
  111. package/cpp/json-schema-to-grammar.cpp +985 -0
  112. package/cpp/json-schema-to-grammar.h +21 -0
  113. package/cpp/llama-adapter.cpp +388 -0
  114. package/cpp/llama-adapter.h +76 -0
  115. package/cpp/llama-arch.cpp +2355 -0
  116. package/cpp/llama-arch.h +499 -0
  117. package/cpp/llama-batch.cpp +875 -0
  118. package/cpp/llama-batch.h +160 -0
  119. package/cpp/llama-chat.cpp +783 -0
  120. package/cpp/llama-chat.h +65 -0
  121. package/cpp/llama-context.cpp +2788 -0
  122. package/cpp/llama-context.h +306 -0
  123. package/cpp/llama-cparams.cpp +5 -0
  124. package/cpp/llama-cparams.h +41 -0
  125. package/cpp/llama-cpp.h +30 -0
  126. package/cpp/llama-grammar.cpp +1229 -0
  127. package/cpp/llama-grammar.h +173 -0
  128. package/cpp/llama-graph.cpp +1891 -0
  129. package/cpp/llama-graph.h +810 -0
  130. package/cpp/llama-hparams.cpp +180 -0
  131. package/cpp/llama-hparams.h +233 -0
  132. package/cpp/llama-impl.cpp +167 -0
  133. package/cpp/llama-impl.h +61 -0
  134. package/cpp/llama-io.cpp +15 -0
  135. package/cpp/llama-io.h +35 -0
  136. package/cpp/llama-kv-cache-iswa.cpp +318 -0
  137. package/cpp/llama-kv-cache-iswa.h +135 -0
  138. package/cpp/llama-kv-cache.cpp +2059 -0
  139. package/cpp/llama-kv-cache.h +374 -0
  140. package/cpp/llama-kv-cells.h +491 -0
  141. package/cpp/llama-memory-hybrid.cpp +258 -0
  142. package/cpp/llama-memory-hybrid.h +137 -0
  143. package/cpp/llama-memory-recurrent.cpp +1146 -0
  144. package/cpp/llama-memory-recurrent.h +179 -0
  145. package/cpp/llama-memory.cpp +59 -0
  146. package/cpp/llama-memory.h +119 -0
  147. package/cpp/llama-mmap.cpp +609 -0
  148. package/cpp/llama-mmap.h +68 -0
  149. package/cpp/llama-model-loader.cpp +1166 -0
  150. package/cpp/llama-model-loader.h +170 -0
  151. package/cpp/llama-model-saver.cpp +282 -0
  152. package/cpp/llama-model-saver.h +37 -0
  153. package/cpp/llama-model.cpp +19061 -0
  154. package/cpp/llama-model.h +491 -0
  155. package/cpp/llama-sampling.cpp +2575 -0
  156. package/cpp/llama-sampling.h +32 -0
  157. package/cpp/llama-vocab.cpp +3792 -0
  158. package/cpp/llama-vocab.h +176 -0
  159. package/cpp/llama.cpp +358 -0
  160. package/cpp/llama.h +1373 -0
  161. package/cpp/log.cpp +428 -0
  162. package/cpp/log.h +103 -0
  163. package/cpp/minja/chat-template.hpp +550 -0
  164. package/cpp/minja/minja.hpp +3009 -0
  165. package/cpp/nlohmann/json.hpp +25526 -0
  166. package/cpp/nlohmann/json_fwd.hpp +187 -0
  167. package/cpp/regex-partial.cpp +204 -0
  168. package/cpp/regex-partial.h +56 -0
  169. package/cpp/sampling.cpp +579 -0
  170. package/cpp/sampling.h +107 -0
  171. package/cpp/tools/mtmd/clip-impl.h +473 -0
  172. package/cpp/tools/mtmd/clip.cpp +4322 -0
  173. package/cpp/tools/mtmd/clip.h +106 -0
  174. package/cpp/tools/mtmd/miniaudio/miniaudio.h +93468 -0
  175. package/cpp/tools/mtmd/mtmd-audio.cpp +769 -0
  176. package/cpp/tools/mtmd/mtmd-audio.h +47 -0
  177. package/cpp/tools/mtmd/mtmd-helper.cpp +460 -0
  178. package/cpp/tools/mtmd/mtmd-helper.h +95 -0
  179. package/cpp/tools/mtmd/mtmd.cpp +1066 -0
  180. package/cpp/tools/mtmd/mtmd.h +302 -0
  181. package/cpp/tools/mtmd/stb/stb_image.h +7988 -0
  182. package/cpp/unicode-data.cpp +7034 -0
  183. package/cpp/unicode-data.h +20 -0
  184. package/cpp/unicode.cpp +1061 -0
  185. package/cpp/unicode.h +68 -0
  186. package/cpp/vendor/cpp-httplib/httplib.cpp +16509 -0
  187. package/cpp/vendor/cpp-httplib/httplib.h +3883 -0
  188. package/desktop/electron-builder.config.cjs +157 -0
  189. package/desktop/entitlements.mac.plist +12 -0
  190. package/desktop/package.json +11 -0
  191. package/desktop/resolve-package-root.cjs +88 -0
  192. package/desktop/src/main/backend-selector.cjs +148 -0
  193. package/desktop/src/main/gpu-probe.cjs +142 -0
  194. package/desktop/src/main/index.cjs +58 -0
  195. package/desktop/src/main/ipc-handlers.cjs +212 -0
  196. package/desktop/src/main/model-store.cjs +50 -0
  197. package/desktop/src/main/preload.cjs +39 -0
  198. package/desktop/src/main/sidecar-client.cjs +76 -0
  199. package/desktop/src/main/sidecar-manager.cjs +364 -0
  200. package/dist/docs.json +14357 -0
  201. package/dist/esm/definitions.d.ts +731 -0
  202. package/dist/esm/definitions.js +2 -0
  203. package/dist/esm/definitions.js.map +1 -0
  204. package/dist/esm/desktop.d.ts +37 -0
  205. package/dist/esm/desktop.js +133 -0
  206. package/dist/esm/desktop.js.map +1 -0
  207. package/dist/esm/index.d.ts +200 -0
  208. package/dist/esm/index.js +612 -0
  209. package/dist/esm/index.js.map +1 -0
  210. package/dist/esm/isomorphic/desktop.runtime.d.ts +37 -0
  211. package/dist/esm/isomorphic/desktop.runtime.js +36 -0
  212. package/dist/esm/isomorphic/desktop.runtime.js.map +1 -0
  213. package/dist/esm/isomorphic/errors.d.ts +6 -0
  214. package/dist/esm/isomorphic/errors.js +9 -0
  215. package/dist/esm/isomorphic/errors.js.map +1 -0
  216. package/dist/esm/isomorphic/model.admission.d.ts +17 -0
  217. package/dist/esm/isomorphic/model.admission.js +27 -0
  218. package/dist/esm/isomorphic/model.admission.js.map +1 -0
  219. package/dist/esm/isomorphic/model.scheduler.d.ts +31 -0
  220. package/dist/esm/isomorphic/model.scheduler.js +95 -0
  221. package/dist/esm/isomorphic/model.scheduler.js.map +1 -0
  222. package/dist/esm/isomorphic/provider.desktop.d.ts +40 -0
  223. package/dist/esm/isomorphic/provider.desktop.js +411 -0
  224. package/dist/esm/isomorphic/provider.desktop.js.map +1 -0
  225. package/dist/esm/isomorphic/provider.factory.d.ts +2 -0
  226. package/dist/esm/isomorphic/provider.factory.js +16 -0
  227. package/dist/esm/isomorphic/provider.factory.js.map +1 -0
  228. package/dist/esm/isomorphic/provider.interface.d.ts +76 -0
  229. package/dist/esm/isomorphic/provider.interface.js +2 -0
  230. package/dist/esm/isomorphic/provider.interface.js.map +1 -0
  231. package/dist/esm/isomorphic/provider.native.d.ts +18 -0
  232. package/dist/esm/isomorphic/provider.native.js +173 -0
  233. package/dist/esm/isomorphic/provider.native.js.map +1 -0
  234. package/dist/esm/isomorphic/provider.web.d.ts +88 -0
  235. package/dist/esm/isomorphic/provider.web.js +573 -0
  236. package/dist/esm/isomorphic/provider.web.js.map +1 -0
  237. package/dist/esm/isomorphic/sidecar-sse.d.ts +14 -0
  238. package/dist/esm/isomorphic/sidecar-sse.js +76 -0
  239. package/dist/esm/isomorphic/sidecar-sse.js.map +1 -0
  240. package/dist/esm/isomorphic/wasmMemoryCalibration.d.ts +26 -0
  241. package/dist/esm/isomorphic/wasmMemoryCalibration.js +60 -0
  242. package/dist/esm/isomorphic/wasmMemoryCalibration.js.map +1 -0
  243. package/dist/esm/isomorphic/wasmMemoryPolicy.d.ts +55 -0
  244. package/dist/esm/isomorphic/wasmMemoryPolicy.js +93 -0
  245. package/dist/esm/isomorphic/wasmMemoryPolicy.js.map +1 -0
  246. package/dist/esm/storage/manifest.d.ts +13 -0
  247. package/dist/esm/storage/manifest.js +87 -0
  248. package/dist/esm/storage/manifest.js.map +1 -0
  249. package/dist/esm/storage/opfs.store.d.ts +31 -0
  250. package/dist/esm/storage/opfs.store.js +241 -0
  251. package/dist/esm/storage/opfs.store.js.map +1 -0
  252. package/dist/esm/web.d.ts +206 -0
  253. package/dist/esm/web.js +521 -0
  254. package/dist/esm/web.js.map +1 -0
  255. package/dist/esm/workers/async-file.d.ts +13 -0
  256. package/dist/esm/workers/async-file.js +12 -0
  257. package/dist/esm/workers/async-file.js.map +1 -0
  258. package/dist/esm/workers/heapfs.d.ts +55 -0
  259. package/dist/esm/workers/heapfs.js +115 -0
  260. package/dist/esm/workers/heapfs.js.map +1 -0
  261. package/dist/esm/workers/wasm.engine.d.ts +86 -0
  262. package/dist/esm/workers/wasm.engine.js +504 -0
  263. package/dist/esm/workers/wasm.engine.js.map +1 -0
  264. package/dist/esm/workers/worker.protocol.d.ts +160 -0
  265. package/dist/esm/workers/worker.protocol.js +2 -0
  266. package/dist/esm/workers/worker.protocol.js.map +1 -0
  267. package/dist/plugin.cjs +3179 -0
  268. package/dist/plugin.cjs.map +1 -0
  269. package/dist/plugin.js +3181 -0
  270. package/dist/plugin.js.map +1 -0
  271. package/dist/wasm/llama_engine.d.ts +74 -0
  272. package/dist/wasm/llama_engine.js +1829 -0
  273. package/dist/wasm/llama_engine.wasm +0 -0
  274. package/dist/wasm/llama_engine_emscripten.mjs +2 -0
  275. package/dist/wasm/package.json +16 -0
  276. package/dist/workers/llm.worker.js +1226 -0
  277. package/dist/workers/llm.worker.js.map +7 -0
  278. package/extraResources/llama-wasm/llama_engine.d.ts +74 -0
  279. package/extraResources/llama-wasm/llama_engine.js +1829 -0
  280. package/extraResources/llama-wasm/llama_engine.wasm +0 -0
  281. package/extraResources/llama-wasm/llama_engine_emscripten.mjs +2 -0
  282. package/extraResources/llama-wasm/package.json +16 -0
  283. package/extraResources/sidecar/README.md +11 -0
  284. package/extraResources/sidecar/darwin-arm64 +0 -0
  285. package/extraResources/sidecar/darwin-x64 +0 -0
  286. package/ios/CMakeLists-arm64.txt +161 -0
  287. package/ios/CMakeLists-x86_64.txt +188 -0
  288. package/ios/CMakeLists.txt +161 -0
  289. package/ios/Frameworks/llama-cpp.framework/Info.plist +28 -0
  290. package/ios/Frameworks/llama-cpp.framework/llama-cpp +0 -0
  291. package/ios/Sources/LlamaCppCapacitor/LlamaCpp.swift +1365 -0
  292. package/ios/Sources/LlamaCppCapacitor/LlamaCppPlugin.swift +694 -0
  293. package/ios/Sources/LlamaCppCapacitor/LlamaNativeBridge.swift +349 -0
  294. package/ios/Sources/LlamaCppCapacitor/ModelAdmissionController.swift +177 -0
  295. package/ios/embed-metal-shaders.sh +24 -0
  296. package/ios/metal-embed.cmake +29 -0
  297. package/package.json +281 -0
  298. package/scripts/build-js-preserve-wasm.cjs +53 -0
  299. package/scripts/build-sidecar-linux.sh +6 -0
  300. package/scripts/build-sidecar-win.bat +19 -0
  301. package/scripts/build-sidecar.sh +184 -0
  302. package/scripts/embed-llama-ios-app-framework.sh +63 -0
  303. package/scripts/ensure-desktop-sidecar-bundle.cjs +103 -0
  304. package/scripts/ensure-llama-ios-xcframework.sh +108 -0
  305. package/scripts/fix-esm-extensions.cjs +45 -0
  306. package/scripts/prepare-js-dist.cjs +28 -0
  307. package/scripts/stage-desktop-resources.cjs +116 -0
  308. package/sidecar/CMakeLists.txt +192 -0
  309. package/sidecar/cap-sidecar-main.cpp +68 -0
  310. package/types/llama-cpp-pro.d.ts +441 -0
@@ -0,0 +1,349 @@
1
+ import Foundation
2
+
3
+ enum LlamaNativeBridge {
4
+ enum Failure: LocalizedError {
5
+ case missingSymbol(String)
6
+ case modelNotFound(String)
7
+ case initializationFailed(String)
8
+ case completionFailed(String)
9
+ case embeddingFailed(String)
10
+ case operationFailed(String)
11
+
12
+ var errorDescription: String? {
13
+ switch self {
14
+ case .missingSymbol(let symbol):
15
+ return "Native symbol \(symbol) is not linked. Rebuild llama-cpp.framework."
16
+ case .modelNotFound(let path):
17
+ return "Model file not found at \(path)"
18
+ case .initializationFailed(let details):
19
+ return "Failed to initialize llama context: \(details)"
20
+ case .completionFailed(let details):
21
+ return "Failed to run local completion: \(details)"
22
+ case .embeddingFailed(let details):
23
+ return "Failed to run local embedding: \(details)"
24
+ case .operationFailed(let details):
25
+ return "Operation failed: \(details)"
26
+ }
27
+ }
28
+ }
29
+
30
+ private typealias InitContextFn = @convention(c) (UnsafePointer<CChar>, UnsafePointer<CChar>) -> Int64
31
+ private typealias ReleaseContextFn = @convention(c) (Int64) -> Void
32
+ private typealias RunCompletionFn = @convention(c) (Int64, UnsafePointer<CChar>) -> UnsafeMutablePointer<CChar>?
33
+ private typealias FreeResultFn = @convention(c) (UnsafeMutablePointer<CChar>) -> Void
34
+ private typealias StopCompletionFn = @convention(c) (Int64) -> Void
35
+ private typealias RunEmbeddingJsonFn = @convention(c) (Int64, UnsafePointer<CChar>, UnsafePointer<CChar>) -> UnsafeMutablePointer<CChar>?
36
+ private typealias JsonOpFn = @convention(c) (Int64, UnsafePointer<CChar>, UnsafePointer<CChar>) -> UnsafeMutablePointer<CChar>?
37
+ private typealias SingleArgJsonFn = @convention(c) (Int64, UnsafePointer<CChar>) -> UnsafeMutablePointer<CChar>?
38
+ private typealias BoolFn = @convention(c) (Int64) -> Int32
39
+ private typealias BoolBoolFn = @convention(c) (Int64, Int32) -> Int32
40
+ private typealias SessionSaveFn = @convention(c) (Int64, UnsafePointer<CChar>, Int32) -> Int32
41
+ private typealias BenchFn = @convention(c) (Int64, Int32, Int32, Int32, Int32) -> UnsafeMutablePointer<CChar>?
42
+ private typealias LoraApplyFn = @convention(c) (Int64, UnsafePointer<CChar>) -> Int32
43
+ private typealias VoidFn = @convention(c) (Int64) -> Void
44
+ private typealias MultimodalInitFn = @convention(c) (Int64, UnsafePointer<CChar>, Int32) -> Int32
45
+ private typealias VocoderInitFn = @convention(c) (Int64, UnsafePointer<CChar>, Int32) -> Int32
46
+
47
+ private static var library: UnsafeMutableRawPointer? = {
48
+ let fm = FileManager.default
49
+ var candidates: [String] = []
50
+ if let fw = Bundle.main.path(forResource: "llama-cpp", ofType: "framework") {
51
+ candidates.append((fw as NSString).appendingPathComponent("llama-cpp"))
52
+ }
53
+ if let exec = Bundle.main.executablePath {
54
+ candidates.append((exec as NSString).deletingLastPathComponent + "/Frameworks/llama-cpp.framework/llama-cpp")
55
+ }
56
+ for path in candidates where fm.fileExists(atPath: path) {
57
+ if let handle = dlopen(path, RTLD_NOW) {
58
+ return handle
59
+ }
60
+ print("[LlamaNativeBridge] dlopen failed for \(path): \(String(cString: dlerror()))")
61
+ }
62
+ print("[LlamaNativeBridge] llama-cpp framework binary not found; tried: \(candidates)")
63
+ return nil
64
+ }()
65
+
66
+ static func sym<T>(_ name: String, _ type: T.Type) throws -> T {
67
+ guard let library else {
68
+ throw Failure.missingSymbol(name)
69
+ }
70
+ guard let pointer = dlsym(library, name) else {
71
+ throw Failure.missingSymbol(name)
72
+ }
73
+ return unsafeBitCast(pointer, to: T.self)
74
+ }
75
+
76
+ static func trySymOpt<T>(_ name: String, _ type: T.Type) -> T? {
77
+ guard let library, let pointer = dlsym(library, name) else { return nil }
78
+ return unsafeBitCast(pointer, to: T.self)
79
+ }
80
+
81
+ // MARK: - Core
82
+
83
+ static func initContext(modelPath: String, paramsJson: String) throws -> Int64 {
84
+ let normalizedPath = normalizeModelPath(modelPath)
85
+ guard FileManager.default.fileExists(atPath: normalizedPath) else {
86
+ throw Failure.modelNotFound(normalizedPath)
87
+ }
88
+ let fn = try sym("llama_init_context", InitContextFn.self)
89
+ let id = normalizedPath.withCString { mp in
90
+ paramsJson.withCString { pj in fn(mp, pj) }
91
+ }
92
+ guard id > 0 else {
93
+ throw Failure.initializationFailed("native loader returned \(id) for \(normalizedPath)")
94
+ }
95
+ return id
96
+ }
97
+
98
+ static func releaseContext(_ contextId: Int64) {
99
+ guard let fn = try? sym("llama_release_context", ReleaseContextFn.self) else { return }
100
+ fn(contextId)
101
+ }
102
+
103
+ static func runCompletion(contextId: Int64, paramsJson: String) throws -> [String: Any] {
104
+ let fn = try sym("llama_run_completion", RunCompletionFn.self)
105
+ let free = try sym("llama_free_completion_result", FreeResultFn.self)
106
+ let ptr = paramsJson.withCString { fn(contextId, $0) }
107
+ guard let ptr else { throw Failure.completionFailed("nil result") }
108
+ defer { free(ptr) }
109
+ return try decodeJsonDictionary(from: ptr, failure: .completionFailed("invalid JSON"))
110
+ }
111
+
112
+ static func runEmbedding(contextId: Int64, text: String, paramsJson: String) throws -> [String: Any] {
113
+ let fn = try sym("llama_run_embedding_json", RunEmbeddingJsonFn.self)
114
+ let free = try sym("llama_free_completion_result", FreeResultFn.self)
115
+ let ptr = text.withCString { t in paramsJson.withCString { p in fn(contextId, t, p) } }
116
+ guard let ptr else { throw Failure.embeddingFailed("nil result") }
117
+ defer { free(ptr) }
118
+ return try decodeJsonDictionary(from: ptr, failure: .embeddingFailed("invalid JSON"))
119
+ }
120
+
121
+ static func stopCompletion(_ contextId: Int64) {
122
+ guard let fn = try? sym("llama_stop_completion", StopCompletionFn.self) else { return }
123
+ fn(contextId)
124
+ }
125
+
126
+ // MARK: - Rerank
127
+
128
+ /// Returns JSON: [{"score": float, "index": int}, ...]
129
+ static func runRerank(contextId: Int64, query: String, documentsJson: String) throws -> [[String: Any]] {
130
+ // llama_rerank_json(context_id, query_cstr, docs_json_cstr) -> char*
131
+ guard let fn: JsonOpFn = trySymOpt("llama_rerank_json", JsonOpFn.self),
132
+ let free: FreeResultFn = trySymOpt("llama_free_completion_result", FreeResultFn.self) else {
133
+ throw Failure.missingSymbol("llama_rerank_json")
134
+ }
135
+ let ptr = query.withCString { q in documentsJson.withCString { d in fn(contextId, q, d) } }
136
+ guard let ptr else { throw Failure.operationFailed("rerank returned nil") }
137
+ defer { free(ptr) }
138
+ let json = String(cString: ptr)
139
+ guard let data = json.data(using: .utf8),
140
+ let arr = try? JSONSerialization.jsonObject(with: data) as? [[String: Any]] else {
141
+ throw Failure.operationFailed("rerank returned invalid JSON")
142
+ }
143
+ return arr
144
+ }
145
+
146
+ // MARK: - Bench
147
+
148
+ /// Returns the raw bench result string "[modelDesc, size, nParams, ppAvg, ppStd, tgAvg, tgStd]"
149
+ static func runBench(contextId: Int64, pp: Int, tg: Int, pl: Int, nr: Int) throws -> String {
150
+ guard let fn: BenchFn = trySymOpt("llama_bench", BenchFn.self),
151
+ let free: FreeResultFn = trySymOpt("llama_free_completion_result", FreeResultFn.self) else {
152
+ throw Failure.missingSymbol("llama_bench")
153
+ }
154
+ let ptr = fn(contextId, Int32(pp), Int32(tg), Int32(pl), Int32(nr))
155
+ guard let ptr else { return "[]" }
156
+ defer { free(ptr) }
157
+ return String(cString: ptr)
158
+ }
159
+
160
+ // MARK: - Session management
161
+
162
+ static func loadSession(contextId: Int64, filepath: String) throws -> [String: Any] {
163
+ guard let fn: SingleArgJsonFn = trySymOpt("llama_cap_load_session_file", SingleArgJsonFn.self),
164
+ let free: FreeResultFn = trySymOpt("llama_free_completion_result", FreeResultFn.self) else {
165
+ throw Failure.missingSymbol("llama_cap_load_session_file")
166
+ }
167
+ let ptr = filepath.withCString { fn(contextId, $0) }
168
+ guard let ptr else { throw Failure.operationFailed("loadSession returned nil for \(filepath)") }
169
+ defer { free(ptr) }
170
+ return try decodeJsonDictionary(from: ptr, failure: .operationFailed("loadSession invalid JSON"))
171
+ }
172
+
173
+ static func saveSession(contextId: Int64, filepath: String, size: Int) throws -> Int {
174
+ guard let fn: SessionSaveFn = trySymOpt("llama_cap_save_session_file", SessionSaveFn.self) else {
175
+ throw Failure.missingSymbol("llama_cap_save_session_file")
176
+ }
177
+ let saved = filepath.withCString { fn(contextId, $0, Int32(size)) }
178
+ return Int(saved)
179
+ }
180
+
181
+ // MARK: - LoRA
182
+
183
+ /// loraAdaptersJson: JSON array [{path:string, scale:float}, ...]
184
+ static func applyLoraAdapters(contextId: Int64, loraAdaptersJson: String) throws -> Int {
185
+ guard let fn: LoraApplyFn = trySymOpt("llama_apply_lora_adapters", LoraApplyFn.self) else {
186
+ throw Failure.missingSymbol("llama_apply_lora_adapters")
187
+ }
188
+ let result = loraAdaptersJson.withCString { fn(contextId, $0) }
189
+ if result < 0 {
190
+ throw Failure.operationFailed("applyLoraAdapters returned \(result)")
191
+ }
192
+ return Int(result)
193
+ }
194
+
195
+ static func removeLoraAdapters(contextId: Int64) throws {
196
+ guard let fn: VoidFn = trySymOpt("llama_remove_lora_adapters", VoidFn.self) else {
197
+ throw Failure.missingSymbol("llama_remove_lora_adapters")
198
+ }
199
+ fn(contextId)
200
+ }
201
+
202
+ static func getLoadedLoraAdapters(contextId: Int64) throws -> [[String: Any]] {
203
+ guard let fn: SingleArgJsonFn = trySymOpt("llama_get_loaded_lora_adapters", SingleArgJsonFn.self),
204
+ let free: FreeResultFn = trySymOpt("llama_free_completion_result", FreeResultFn.self) else {
205
+ throw Failure.missingSymbol("llama_get_loaded_lora_adapters")
206
+ }
207
+ // fn takes (contextId, empty_cstr) — use "" as placeholder
208
+ let ptr = "".withCString { fn(contextId, $0) }
209
+ guard let ptr else { return [] }
210
+ defer { free(ptr) }
211
+ let json = String(cString: ptr)
212
+ guard let data = json.data(using: .utf8),
213
+ let arr = try? JSONSerialization.jsonObject(with: data) as? [[String: Any]] else {
214
+ return []
215
+ }
216
+ return arr
217
+ }
218
+
219
+ // MARK: - Multimodal
220
+
221
+ static func initMultimodal(contextId: Int64, mmProjPath: String, useGpu: Bool) throws -> Bool {
222
+ guard let fn: MultimodalInitFn = trySymOpt("llama_init_multimodal", MultimodalInitFn.self) else {
223
+ throw Failure.missingSymbol("llama_init_multimodal")
224
+ }
225
+ let result = mmProjPath.withCString { fn(contextId, $0, useGpu ? 1 : 0) }
226
+ return result != 0
227
+ }
228
+
229
+ static func isMultimodalEnabled(contextId: Int64) -> Bool {
230
+ guard let fn: BoolFn = trySymOpt("llama_is_multimodal_enabled", BoolFn.self) else { return false }
231
+ return fn(contextId) != 0
232
+ }
233
+
234
+ static func getMultimodalSupport(contextId: Int64) throws -> [String: Any] {
235
+ guard let fn: SingleArgJsonFn = trySymOpt("llama_get_multimodal_support", SingleArgJsonFn.self),
236
+ let free: FreeResultFn = trySymOpt("llama_free_completion_result", FreeResultFn.self) else {
237
+ throw Failure.missingSymbol("llama_get_multimodal_support")
238
+ }
239
+ let ptr = "".withCString { fn(contextId, $0) }
240
+ guard let ptr else { return ["vision": false, "audio": false] }
241
+ defer { free(ptr) }
242
+ return (try? decodeJsonDictionary(from: ptr, failure: .operationFailed("bad JSON"))) ?? ["vision": false, "audio": false]
243
+ }
244
+
245
+ static func releaseMultimodal(contextId: Int64) {
246
+ guard let fn: VoidFn = trySymOpt("llama_release_multimodal", VoidFn.self) else { return }
247
+ fn(contextId)
248
+ }
249
+
250
+ // MARK: - TTS / Vocoder
251
+
252
+ static func initVocoder(contextId: Int64, path: String, nBatch: Int) throws -> Bool {
253
+ guard let fn: VocoderInitFn = trySymOpt("llama_init_vocoder", VocoderInitFn.self) else {
254
+ throw Failure.missingSymbol("llama_init_vocoder")
255
+ }
256
+ let result = path.withCString { fn(contextId, $0, Int32(nBatch)) }
257
+ return result != 0
258
+ }
259
+
260
+ static func isVocoderEnabled(contextId: Int64) -> Bool {
261
+ guard let fn: BoolFn = trySymOpt("llama_is_vocoder_enabled", BoolFn.self) else { return false }
262
+ return fn(contextId) != 0
263
+ }
264
+
265
+ static func getFormattedAudioCompletion(contextId: Int64, speakerJson: String, text: String) throws -> [String: Any] {
266
+ guard let fn: JsonOpFn = trySymOpt("llama_get_formatted_audio_completion", JsonOpFn.self),
267
+ let free: FreeResultFn = trySymOpt("llama_free_completion_result", FreeResultFn.self) else {
268
+ throw Failure.missingSymbol("llama_get_formatted_audio_completion")
269
+ }
270
+ let ptr = speakerJson.withCString { sp in text.withCString { tx in fn(contextId, sp, tx) } }
271
+ guard let ptr else { throw Failure.operationFailed("getFormattedAudioCompletion returned nil") }
272
+ defer { free(ptr) }
273
+ return try decodeJsonDictionary(from: ptr, failure: .operationFailed("audio completion invalid JSON"))
274
+ }
275
+
276
+ static func getAudioCompletionGuideTokens(contextId: Int64, text: String) throws -> [Int] {
277
+ guard let fn: SingleArgJsonFn = trySymOpt("llama_get_audio_completion_guide_tokens", SingleArgJsonFn.self),
278
+ let free: FreeResultFn = trySymOpt("llama_free_completion_result", FreeResultFn.self) else {
279
+ throw Failure.missingSymbol("llama_get_audio_completion_guide_tokens")
280
+ }
281
+ let ptr = text.withCString { fn(contextId, $0) }
282
+ guard let ptr else { return [] }
283
+ defer { free(ptr) }
284
+ let json = String(cString: ptr)
285
+ guard let data = json.data(using: .utf8),
286
+ let arr = try? JSONSerialization.jsonObject(with: data) as? [Int] else { return [] }
287
+ return arr
288
+ }
289
+
290
+ static func decodeAudioTokens(contextId: Int64, tokensJson: String) throws -> [Float] {
291
+ guard let fn: SingleArgJsonFn = trySymOpt("llama_decode_audio_tokens", SingleArgJsonFn.self),
292
+ let free: FreeResultFn = trySymOpt("llama_free_completion_result", FreeResultFn.self) else {
293
+ throw Failure.missingSymbol("llama_decode_audio_tokens")
294
+ }
295
+ let ptr = tokensJson.withCString { fn(contextId, $0) }
296
+ guard let ptr else { return [] }
297
+ defer { free(ptr) }
298
+ let json = String(cString: ptr)
299
+ guard let data = json.data(using: .utf8),
300
+ let arr = try? JSONSerialization.jsonObject(with: data) as? [Double] else { return [] }
301
+ return arr.map { Float($0) }
302
+ }
303
+
304
+ static func releaseVocoder(contextId: Int64) {
305
+ guard let fn: VoidFn = trySymOpt("llama_release_vocoder", VoidFn.self) else { return }
306
+ fn(contextId)
307
+ }
308
+
309
+ // MARK: - GPU info
310
+
311
+ /// Returns {"gpu": bool, "reasonNoGPU": string} from native context model JSON
312
+ static func queryGpuInfo(contextId: Int64) -> (gpu: Bool, reason: String) {
313
+ guard let fn: SingleArgJsonFn = trySymOpt("llama_get_context_gpu_info", SingleArgJsonFn.self),
314
+ let free: FreeResultFn = trySymOpt("llama_free_completion_result", FreeResultFn.self) else {
315
+ return (false, "llama_get_context_gpu_info not available")
316
+ }
317
+ let ptr = "".withCString { fn(contextId, $0) }
318
+ guard let ptr else { return (false, "no GPU info returned") }
319
+ defer { free(ptr) }
320
+ let json = String(cString: ptr)
321
+ guard let data = json.data(using: .utf8),
322
+ let d = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
323
+ return (false, "GPU info JSON parse error")
324
+ }
325
+ let gpu = (d["gpu"] as? Bool) ?? false
326
+ let reason = (d["reasonNoGPU"] as? String) ?? (gpu ? "" : "Metal/GPU not available")
327
+ return (gpu, reason)
328
+ }
329
+
330
+ // MARK: - Helpers
331
+
332
+ static func decodeJsonDictionary(
333
+ from resultPointer: UnsafeMutablePointer<CChar>,
334
+ failure: Failure
335
+ ) throws -> [String: Any] {
336
+ let jsonString = String(cString: resultPointer)
337
+ guard let data = jsonString.data(using: .utf8) else { throw failure }
338
+ let object = try JSONSerialization.jsonObject(with: data, options: [])
339
+ guard let dictionary = object as? [String: Any] else { throw failure }
340
+ return dictionary
341
+ }
342
+
343
+ static func normalizeModelPath(_ modelPath: String) -> String {
344
+ if modelPath.hasPrefix("file://") {
345
+ return String(modelPath.dropFirst("file://".count))
346
+ }
347
+ return modelPath
348
+ }
349
+ }
@@ -0,0 +1,177 @@
1
+ import Foundation
2
+
3
+ /// Memory admission control for native model loading on iOS.
4
+ ///
5
+ /// This mirrors the Web/WASM `DefaultModelScheduler` + `wasmMemoryPolicy` so that all
6
+ /// three platforms share the same isomorphic admission semantics:
7
+ /// - A hard cap on concurrent loaded models (parity with `WASM_MAX_CONCURRENT_MODELS = 5`).
8
+ /// - Per-model footprint estimation based on GGUF file size.
9
+ /// - A device-memory guard that keeps a reserve free after each load.
10
+ ///
11
+ /// Unlike the Web path (bounded by a single 2 GB WASM linear-memory pool), the iOS
12
+ /// ceiling is the per-process memory budget reported by `os_proc_available_memory()`
13
+ /// (the headroom before jetsam terminates the app). The controller rejects a load when
14
+ /// either the slot limit is reached or the projected available memory after loading
15
+ /// would fall below the reserve threshold.
16
+ final class ModelAdmissionController {
17
+
18
+ /// Max concurrent native contexts. Parity with `WASM_MAX_CONCURRENT_MODELS`.
19
+ static let maxConcurrentModels = 5
20
+
21
+ /// Keep this much process memory free after a model load (headroom for app + OS).
22
+ static let defaultReserveBytes: UInt64 = 512 * 1024 * 1024 // 512 MB
23
+
24
+ /// Fallback footprint when the GGUF size cannot be determined.
25
+ private static let unknownModelFootprintBytes: UInt64 = 512 * 1024 * 1024
26
+
27
+ enum DeniedBy {
28
+ case limit
29
+ case memory
30
+ }
31
+
32
+ /// Result of an admission decision.
33
+ struct Decision {
34
+ let allow: Bool
35
+ let deniedBy: DeniedBy? // nil when allowed
36
+ let reason: String? // nil when allowed
37
+ let estimatedBytes: UInt64
38
+
39
+ static func allowed(_ estimatedBytes: UInt64) -> Decision {
40
+ Decision(allow: true, deniedBy: nil, reason: nil, estimatedBytes: estimatedBytes)
41
+ }
42
+
43
+ static func denied(_ deniedBy: DeniedBy, _ reason: String, _ estimatedBytes: UInt64) -> Decision {
44
+ Decision(allow: false, deniedBy: deniedBy, reason: reason, estimatedBytes: estimatedBytes)
45
+ }
46
+ }
47
+
48
+ /// Lightweight snapshot of process/device memory (mirrors the Web MemorySnapshot).
49
+ struct MemorySnapshot {
50
+ let totalBytes: UInt64 // device physical memory
51
+ let freeBytes: UInt64 // per-process available memory (headroom before jetsam)
52
+ }
53
+
54
+ private let maxModels: Int
55
+ private let reserveBytes: UInt64
56
+
57
+ init(maxModels: Int = ModelAdmissionController.maxConcurrentModels,
58
+ reserveBytes: UInt64 = ModelAdmissionController.defaultReserveBytes) {
59
+ self.maxModels = maxModels
60
+ self.reserveBytes = reserveBytes
61
+ }
62
+
63
+ var maxModelCount: Int { maxModels }
64
+
65
+ /// Estimate the resident footprint of a model once loaded.
66
+ ///
67
+ /// Native loading (mmap or full read) does not duplicate the GGUF the way a naive
68
+ /// heap copy would, but the KV cache and compute buffers add headroom on top of the
69
+ /// mapped weights. The multipliers below match the WASM policy's intent, scaled for
70
+ /// native memory behaviour.
71
+ ///
72
+ /// - Parameters:
73
+ /// - fileBytes: GGUF file size in bytes (0 when unknown)
74
+ /// - embedding: whether the context is an embedding-only model (lighter headroom)
75
+ static func estimateModelFootprint(fileBytes: UInt64, embedding: Bool) -> UInt64 {
76
+ guard fileBytes > 0 else {
77
+ return unknownModelFootprintBytes
78
+ }
79
+ let isLarge = fileBytes > 200 * 1024 * 1024
80
+ let weightMultiplier: Double = embedding ? 1.15 : (isLarge ? 1.30 : 1.20)
81
+ let proportionalHeadroom = UInt64((Double(fileBytes) * 0.12).rounded(.up))
82
+ let minHeadroom: UInt64 = embedding ? 48 * 1024 * 1024 : 96 * 1024 * 1024
83
+ let headroom = max(minHeadroom, proportionalHeadroom)
84
+ let weights = UInt64((Double(fileBytes) * weightMultiplier).rounded(.up))
85
+ return weights + headroom
86
+ }
87
+
88
+ /// Read the GGUF file size, returning 0 when the path is missing or unreadable.
89
+ static func fileSizeBytes(_ modelPath: String) -> UInt64 {
90
+ guard !modelPath.isEmpty else { return 0 }
91
+ // Accept both plain paths and file:// URLs.
92
+ let path: String
93
+ if let url = URL(string: modelPath), url.isFileURL {
94
+ path = url.path
95
+ } else {
96
+ path = modelPath
97
+ }
98
+ do {
99
+ let attrs = try FileManager.default.attributesOfItem(atPath: path)
100
+ if let size = attrs[.size] as? NSNumber {
101
+ return size.uint64Value
102
+ }
103
+ } catch {
104
+ return 0
105
+ }
106
+ return 0
107
+ }
108
+
109
+ /// Capture a process/device memory snapshot.
110
+ ///
111
+ /// `os_proc_available_memory()` (iOS 13+) reports the memory the app can still use
112
+ /// before jetsam terminates it — a more meaningful guard than device-wide free RAM.
113
+ func memorySnapshot() -> MemorySnapshot {
114
+ let total = ProcessInfo.processInfo.physicalMemory
115
+ var free: UInt64 = 0
116
+ if #available(iOS 13.0, *) {
117
+ let available = os_proc_available_memory()
118
+ if available > 0 {
119
+ free = UInt64(available)
120
+ }
121
+ }
122
+ return MemorySnapshot(totalBytes: total, freeBytes: free)
123
+ }
124
+
125
+ /// Decide whether a new model may be admitted.
126
+ ///
127
+ /// - Parameters:
128
+ /// - currentlyLoaded: number of contexts already loaded
129
+ /// - modelPath: path to the GGUF being loaded (used to size the footprint)
130
+ /// - embedding: whether this is an embedding-only context
131
+ func canAdmit(currentlyLoaded: Int, modelPath: String, embedding: Bool) -> Decision {
132
+ let fileBytes = Self.fileSizeBytes(modelPath)
133
+ let estimated = Self.estimateModelFootprint(fileBytes: fileBytes, embedding: embedding)
134
+
135
+ // 1. Slot limit (parity with Web).
136
+ if currentlyLoaded >= maxModels {
137
+ return .denied(
138
+ .limit,
139
+ "Model slot limit reached (\(maxModels) concurrent contexts)",
140
+ estimated
141
+ )
142
+ }
143
+
144
+ // 2. Process-memory guard: keep `reserveBytes` free after the load.
145
+ let mem = memorySnapshot()
146
+ if mem.freeBytes > 0 {
147
+ // Guard against unsigned underflow.
148
+ if mem.freeBytes <= estimated || (mem.freeBytes - estimated) < reserveBytes {
149
+ return .denied(
150
+ .memory,
151
+ "Insufficient memory: need ~\(toMb(estimated)) MB, "
152
+ + "\(toMb(mem.freeBytes)) MB available, "
153
+ + "\(toMb(reserveBytes)) MB reserve required",
154
+ estimated
155
+ )
156
+ }
157
+ }
158
+
159
+ return .allowed(estimated)
160
+ }
161
+
162
+ /// Snapshot of admission state for diagnostics / health reporting.
163
+ func status(currentlyLoaded: Int) -> [String: Any] {
164
+ let mem = memorySnapshot()
165
+ return [
166
+ "loadedModels": currentlyLoaded,
167
+ "maxModels": maxModels,
168
+ "deviceTotalBytes": mem.totalBytes,
169
+ "processFreeBytes": mem.freeBytes,
170
+ "reserveBytes": reserveBytes
171
+ ]
172
+ }
173
+
174
+ private func toMb(_ bytes: UInt64) -> UInt64 {
175
+ bytes / (1024 * 1024)
176
+ }
177
+ }
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env bash
2
+ # Merge ggml headers into ggml-metal.metal and emit assembly that embeds the source
3
+ # for LM_GGML_METAL_EMBED_LIBRARY (runtime Metal shader compilation).
4
+ set -euo pipefail
5
+
6
+ COMMON="$1"
7
+ SOURCE="$2"
8
+ IMPL="$3"
9
+ OUT_ASM="$4"
10
+ OUT_METAL="$5"
11
+ TMP_METAL="${OUT_METAL}.tmp"
12
+
13
+ sed -e "/__embed_ggml-common.h__/r ${COMMON}" -e "/__embed_ggml-common.h__/d" < "${SOURCE}" > "${TMP_METAL}"
14
+ sed -e "/#include \"ggml-metal-impl.h\"/r ${IMPL}" -e "/#include \"ggml-metal-impl.h\"/d" < "${TMP_METAL}" > "${OUT_METAL}"
15
+ rm -f "${TMP_METAL}"
16
+
17
+ cat > "${OUT_ASM}" <<EOF
18
+ .section __DATA,__ggml_metallib
19
+ .globl _lm_ggml_metallib_start
20
+ _lm_ggml_metallib_start:
21
+ .incbin "${OUT_METAL}"
22
+ .globl _lm_ggml_metallib_end
23
+ _lm_ggml_metallib_end:
24
+ EOF
@@ -0,0 +1,29 @@
1
+ # Embed ggml-metal.metal (with merged headers) for LM_GGML_METAL_EMBED_LIBRARY.
2
+ # Runtime compiles shaders from the embedded source — no default.metallib bundle needed.
3
+
4
+ set(METALLIB_COMMON "${SOURCE_DIR}/ggml-common.h")
5
+ set(METALLIB_SOURCE "${SOURCE_DIR}/ggml-metal.metal")
6
+ set(METALLIB_IMPL "${SOURCE_DIR}/ggml-metal-impl.h")
7
+ set(METALLIB_EMBED_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/embed-metal-shaders.sh")
8
+
9
+ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/autogenerated")
10
+
11
+ set(METALLIB_EMBED_ASM "${CMAKE_CURRENT_BINARY_DIR}/autogenerated/ggml-metal-embed.s")
12
+ set(METALLIB_SOURCE_EMBED "${CMAKE_CURRENT_BINARY_DIR}/autogenerated/ggml-metal-embed.metal")
13
+
14
+ add_custom_command(
15
+ OUTPUT "${METALLIB_EMBED_ASM}"
16
+ COMMAND "${METALLIB_EMBED_SCRIPT}"
17
+ "${METALLIB_COMMON}"
18
+ "${METALLIB_SOURCE}"
19
+ "${METALLIB_IMPL}"
20
+ "${METALLIB_EMBED_ASM}"
21
+ "${METALLIB_SOURCE_EMBED}"
22
+ DEPENDS
23
+ "${METALLIB_EMBED_SCRIPT}"
24
+ "${METALLIB_COMMON}"
25
+ "${METALLIB_SOURCE}"
26
+ "${METALLIB_IMPL}"
27
+ COMMENT "Generate assembly for embedded Metal shader source"
28
+ VERBATIM
29
+ )