commands.go raw

   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