Files
ollama/llm/llama_binary.go
Daniel Hiltgen 98acec40ae create: add server-side MLX imports and drop GGUF conversion (#14969)
* create: add server-side MLX imports and drop GGUF conversion

Support safetensors imports through the MLX create pipeline both locally and on the server, including remote upload/staging, draft layer handling, cancellation propagation, transfer limits, and shared manifest/blob writing.

Limit GGUF create to wrapping existing GGUF inputs into Ollama manifests. Remove the in-tree safetensors-to-GGUF converter, server quantization path, and converter-only dependencies so GGUF conversion and quantization stay in llama.cpp tooling.

Keep the MLX path focused on supported safetensors model creation with validation before MLX work, and expose that flow without the --experimental CLI gate.

* address comments

* add client side gguf create fast path

* address comments

* rebase adjustments
2026-09-14 20:32:36 -07:00

163 lines
3.9 KiB
Go

package llm
import (
"os"
"path/filepath"
"runtime"
"slices"
"strings"
"github.com/ollama/ollama/ml"
)
type llamaCppBinarySearch struct {
libOllamaPath string
executable string
workingDir string
goos string
goarch string
}
func defaultLlamaCppBinarySearch() llamaCppBinarySearch {
executable, _ := os.Executable()
if executable != "" {
if eval, err := filepath.EvalSymlinks(executable); err == nil {
executable = eval
}
}
workingDir, _ := os.Getwd()
return llamaCppBinarySearch{
libOllamaPath: ml.LibOllamaPath,
executable: executable,
workingDir: workingDir,
goos: runtime.GOOS,
goarch: runtime.GOARCH,
}
}
func findLlamaCppBinary(name string, search llamaCppBinarySearch) (string, []string, error) {
candidates := llamaCppBinaryCandidates(name, search)
for _, path := range candidates {
if _, err := os.Stat(path); err == nil {
return path, candidates, nil
}
}
return "", candidates, os.ErrNotExist
}
func llamaCppBinaryCandidates(name string, search llamaCppBinarySearch) []string {
goos := search.goos
if goos == "" {
goos = runtime.GOOS
}
goarch := search.goarch
if goarch == "" {
goarch = runtime.GOARCH
}
suffix := llamaCppBinaryName(name, goos)
seen := map[string]bool{}
var candidates []string
add := func(dir string) {
if dir == "" {
return
}
path := filepath.Clean(filepath.Join(dir, suffix))
if !seen[path] {
seen[path] = true
candidates = append(candidates, path)
}
}
add(search.libOllamaPath)
addPackagedLayoutDirs := func(base string) {
if base == "" {
return
}
switch goos {
case "darwin":
// macOS tarballs and apps colocate llama.cpp helpers with ollama.
add(base)
// Per-architecture local dist output keeps helpers under lib/ollama.
add(filepath.Join(base, "lib", "ollama"))
// Standard CMake installs put ollama in bin/ and helpers in ../lib/ollama/.
add(filepath.Join(base, "..", "lib", "ollama"))
case "linux":
// Linux packages install ollama in bin/ and helpers in ../lib/ollama/.
add(filepath.Join(base, "..", "lib", "ollama"))
case "windows":
// Windows packages keep ollama.exe at top level with lib/ as a peer.
add(filepath.Join(base, "lib", "ollama"))
// Standard CMake installs put ollama.exe in bin/ and helpers in ../lib/ollama/.
add(filepath.Join(base, "..", "lib", "ollama"))
default:
add(filepath.Join(base, "lib", "ollama"))
add(filepath.Join(base, "..", "lib", "ollama"))
}
}
addLocalLayoutDirs := func(base string) {
if base == "" {
return
}
add(filepath.Join(base, "build", "lib", "ollama"))
add(filepath.Join(base, "dist", goos+"-"+goarch, "lib", "ollama"))
if goos+"_"+goarch != goos+"-"+goarch {
add(filepath.Join(base, "dist", goos+"_"+goarch, "lib", "ollama"))
}
if goos == "darwin" {
add(filepath.Join(base, "dist", "darwin"))
}
}
if search.executable != "" {
exeDir := filepath.Dir(search.executable)
addPackagedLayoutDirs(exeDir)
addLocalLayoutDirs(exeDir)
}
if search.workingDir != "" {
addLocalLayoutDirs(search.workingDir)
}
addBuildOutputDirs := func(base string) {
if base == "" {
return
}
matches, _ := filepath.Glob(filepath.Join(base, "build", "llama-server-*", "bin"))
slices.SortFunc(matches, func(a, b string) int {
if rank := llamaCppBuildOutputRank(a) - llamaCppBuildOutputRank(b); rank != 0 {
return rank
}
return strings.Compare(a, b)
})
for _, m := range matches {
add(m)
}
}
if search.executable != "" {
addBuildOutputDirs(filepath.Dir(search.executable))
}
addBuildOutputDirs(search.workingDir)
return candidates
}
func llamaCppBinaryName(name, goos string) string {
if goos == "windows" && filepath.Ext(name) == "" {
return name + ".exe"
}
return name
}
func llamaCppBuildOutputRank(path string) int {
if strings.Contains(path, "llama-server-darwin") ||
strings.Contains(path, "llama-server-cuda") ||
strings.Contains(path, "llama-server-rocm") {
return 0
}
return 1
}