1 package builder
2 3 import (
4 "errors"
5 "fmt"
6 "os/exec"
7 "runtime"
8 "strings"
9 10 "tinygo.org/x/go-llvm"
11 )
12 13 // Commands lists command alternatives for various operating systems. These
14 // commands may have a slightly different name across operating systems and
15 // distributions or may not even exist in $PATH, in which case absolute paths
16 // may be used.
17 var commands = map[string][]string{}
18 19 func init() {
20 llvmMajor := strings.Split(llvm.Version, ".")[0]
21 commands["clang"] = []string{"clang-" + llvmMajor}
22 commands["ld.lld"] = []string{"ld.lld-" + llvmMajor, "ld.lld"}
23 commands["wasm-ld"] = []string{"wasm-ld-" + llvmMajor, "wasm-ld"}
24 commands["lldb"] = []string{"lldb-" + llvmMajor, "lldb"}
25 // Add the path to a Homebrew-installed LLVM for ease of use (no need to
26 // manually set $PATH).
27 if runtime.GOOS == "darwin" {
28 var prefix string
29 switch runtime.GOARCH {
30 case "amd64":
31 prefix = "/usr/local/opt/llvm@" + llvmMajor + "/bin/"
32 case "arm64":
33 prefix = "/opt/homebrew/opt/llvm@" + llvmMajor + "/bin/"
34 default:
35 // unknown GOARCH
36 panic(fmt.Sprintf("unknown GOARCH: %s on darwin", runtime.GOARCH))
37 }
38 commands["clang"] = append(commands["clang"], prefix+"clang-"+llvmMajor)
39 commands["ld.lld"] = append(commands["ld.lld"], prefix+"ld.lld")
40 commands["wasm-ld"] = append(commands["wasm-ld"], prefix+"wasm-ld")
41 commands["lldb"] = append(commands["lldb"], prefix+"lldb")
42 }
43 // Add the path for when LLVM was installed with the installer from
44 // llvm.org, which by default doesn't add LLVM to the $PATH environment
45 // variable.
46 if runtime.GOOS == "windows" {
47 commands["clang"] = append(commands["clang"], "clang", "C:\\Program Files\\LLVM\\bin\\clang.exe")
48 commands["ld.lld"] = append(commands["ld.lld"], "lld", "C:\\Program Files\\LLVM\\bin\\lld.exe")
49 commands["wasm-ld"] = append(commands["wasm-ld"], "C:\\Program Files\\LLVM\\bin\\wasm-ld.exe")
50 commands["lldb"] = append(commands["lldb"], "C:\\Program Files\\LLVM\\bin\\lldb.exe")
51 }
52 // Add the path to LLVM installed from ports.
53 if runtime.GOOS == "freebsd" {
54 prefix := "/usr/local/llvm" + llvmMajor + "/bin/"
55 commands["clang"] = append(commands["clang"], prefix+"clang-"+llvmMajor)
56 commands["ld.lld"] = append(commands["ld.lld"], prefix+"ld.lld")
57 commands["wasm-ld"] = append(commands["wasm-ld"], prefix+"wasm-ld")
58 commands["lldb"] = append(commands["lldb"], prefix+"lldb")
59 }
60 }
61 62 // LookupCommand looks up the executable name for a given LLVM tool such as
63 // clang or wasm-ld. It returns the (relative) command that can be used to
64 // invoke the tool or an error if it could not be found.
65 func LookupCommand(name string) (string, error) {
66 for _, cmdName := range commands[name] {
67 _, err := exec.LookPath(cmdName)
68 if err != nil {
69 if errors.Unwrap(err) == exec.ErrNotFound {
70 continue
71 }
72 return cmdName, err
73 }
74 return cmdName, nil
75 }
76 return "", errors.New("none of these commands were found in your $PATH: " + strings.Join(commands[name], " "))
77 }
78