Files
ollama--ollama/llm/llama_binary.go
T
2026-07-13 11:56:09 +08:00

174 lines
4.3 KiB
Go

package llm
import (
"fmt"
"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,
}
}
// FindLlamaCppBinary locates a llama.cpp helper binary in installed and local
// development layouts.
func FindLlamaCppBinary(name string) (string, error) {
path, candidates, err := findLlamaCppBinary(name, defaultLlamaCppBinarySearch())
if err != nil {
return "", fmt.Errorf("%s binary not found (checked: %s)", name, strings.Join(candidates, ", "))
}
return path, nil
}
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
}