main: refactor environment variables into a separate package
This makes it possible to query these environment variables from anywhere, which might be useful. More importantly, it puts them in a central location from where they can be queried, useful for a `go env` subcommand.
Этот коммит содержится в:
родитель
2a71aa90bc
коммит
2463153a8c
7 изменённых файлов: 214 добавлений и 173 удалений
|
@ -5,16 +5,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
)
|
|
||||||
|
|
||||||
// Get the cache directory, usually ~/.cache/tinygo
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
func cacheDir() string {
|
)
|
||||||
dir, err := os.UserCacheDir()
|
|
||||||
if err != nil {
|
|
||||||
panic("could not find cache dir: " + err.Error())
|
|
||||||
}
|
|
||||||
return filepath.Join(dir, "tinygo")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the newest timestamp of all the file paths passed in. Used to check
|
// Return the newest timestamp of all the file paths passed in. Used to check
|
||||||
// for stale caches.
|
// for stale caches.
|
||||||
|
@ -41,8 +34,7 @@ func cacheTimestamp(paths []string) (time.Time, error) {
|
||||||
// TODO: the configKey is currently ignored. It is supposed to be used as extra
|
// TODO: the configKey is currently ignored. It is supposed to be used as extra
|
||||||
// data for the cache key, like the compiler version and arguments.
|
// data for the cache key, like the compiler version and arguments.
|
||||||
func cacheLoad(name, configKey string, sourceFiles []string) (string, error) {
|
func cacheLoad(name, configKey string, sourceFiles []string) (string, error) {
|
||||||
dir := cacheDir()
|
cachepath := filepath.Join(goenv.Get("GOCACHE"), name)
|
||||||
cachepath := filepath.Join(dir, name)
|
|
||||||
cacheStat, err := os.Stat(cachepath)
|
cacheStat, err := os.Stat(cachepath)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return "", nil // does not exist
|
return "", nil // does not exist
|
||||||
|
@ -76,7 +68,7 @@ func cacheStore(tmppath, name, configKey string, sourceFiles []string) (string,
|
||||||
|
|
||||||
// TODO: check the config key
|
// TODO: check the config key
|
||||||
|
|
||||||
dir := cacheDir()
|
dir := goenv.Get("GOCACHE")
|
||||||
err := os.MkdirAll(dir, 0777)
|
err := os.MkdirAll(dir, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/blakesmith/ar"
|
"github.com/blakesmith/ar"
|
||||||
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// These are the GENERIC_SOURCES according to CMakeList.txt.
|
// These are the GENERIC_SOURCES according to CMakeList.txt.
|
||||||
|
@ -169,13 +170,13 @@ func builtinFiles(target string) []string {
|
||||||
|
|
||||||
// builtinsDir returns the directory where the sources for compiler-rt are kept.
|
// builtinsDir returns the directory where the sources for compiler-rt are kept.
|
||||||
func builtinsDir() string {
|
func builtinsDir() string {
|
||||||
return filepath.Join(sourceDir(), "lib", "compiler-rt", "lib", "builtins")
|
return filepath.Join(goenv.Get("TINYGOROOT"), "lib", "compiler-rt", "lib", "builtins")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the builtins archive, possibly generating it as needed.
|
// Get the builtins archive, possibly generating it as needed.
|
||||||
func loadBuiltins(target string) (path string, err error) {
|
func loadBuiltins(target string) (path string, err error) {
|
||||||
// Try to load a precompiled compiler-rt library.
|
// Try to load a precompiled compiler-rt library.
|
||||||
precompiledPath := filepath.Join(sourceDir(), "pkg", target, "compiler-rt.a")
|
precompiledPath := filepath.Join(goenv.Get("TINYGOROOT"), "pkg", target, "compiler-rt.a")
|
||||||
if _, err := os.Stat(precompiledPath); err == nil {
|
if _, err := os.Stat(precompiledPath); err == nil {
|
||||||
// Found a precompiled compiler-rt for this OS/architecture. Return the
|
// Found a precompiled compiler-rt for this OS/architecture. Return the
|
||||||
// path directly.
|
// path directly.
|
||||||
|
|
189
goenv/goenv.go
Обычный файл
189
goenv/goenv.go
Обычный файл
|
@ -0,0 +1,189 @@
|
||||||
|
// Package goenv returns environment variables that are used in various parts of
|
||||||
|
// the compiler. You can query it manually with the `tinygo env` subcommand.
|
||||||
|
package goenv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"os/user"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Keys is a slice of all available environment variable keys.
|
||||||
|
var Keys = []string{
|
||||||
|
"GOOS",
|
||||||
|
"GOARCH",
|
||||||
|
"GOROOT",
|
||||||
|
"GOPATH",
|
||||||
|
"GOCACHE",
|
||||||
|
"TINYGOROOT",
|
||||||
|
}
|
||||||
|
|
||||||
|
// TINYGOROOT is the path to the final location for checking tinygo files. If
|
||||||
|
// unset (by a -X ldflag), then sourceDir() will fallback to the original build
|
||||||
|
// directory.
|
||||||
|
var TINYGOROOT string
|
||||||
|
|
||||||
|
// Get returns a single environment variable, possibly calculating it on-demand.
|
||||||
|
// The empty string is returned for unknown environment variables.
|
||||||
|
func Get(name string) string {
|
||||||
|
switch name {
|
||||||
|
case "GOOS":
|
||||||
|
if dir := os.Getenv("GOOS"); dir != "" {
|
||||||
|
return dir
|
||||||
|
}
|
||||||
|
return runtime.GOOS
|
||||||
|
case "GOARCH":
|
||||||
|
if dir := os.Getenv("GOARCH"); dir != "" {
|
||||||
|
return dir
|
||||||
|
}
|
||||||
|
return runtime.GOARCH
|
||||||
|
case "GOROOT":
|
||||||
|
return getGoroot()
|
||||||
|
case "GOPATH":
|
||||||
|
if dir := os.Getenv("GOPATH"); dir != "" {
|
||||||
|
return dir
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback
|
||||||
|
home := getHomeDir()
|
||||||
|
return filepath.Join(home, "go")
|
||||||
|
case "GOCACHE":
|
||||||
|
// Get the cache directory, usually ~/.cache/tinygo
|
||||||
|
dir, err := os.UserCacheDir()
|
||||||
|
if err != nil {
|
||||||
|
panic("could not find cache dir: " + err.Error())
|
||||||
|
}
|
||||||
|
return filepath.Join(dir, "tinygo")
|
||||||
|
case "TINYGOROOT":
|
||||||
|
return sourceDir()
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the TINYGOROOT, or exit with an error.
|
||||||
|
func sourceDir() string {
|
||||||
|
// Use $TINYGOROOT as root, if available.
|
||||||
|
root := os.Getenv("TINYGOROOT")
|
||||||
|
if root != "" {
|
||||||
|
if !isSourceDir(root) {
|
||||||
|
fmt.Fprintln(os.Stderr, "error: $TINYGOROOT was not set to the correct root")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
|
if TINYGOROOT != "" {
|
||||||
|
if !isSourceDir(TINYGOROOT) {
|
||||||
|
fmt.Fprintln(os.Stderr, "error: TINYGOROOT was not set to the correct root")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return TINYGOROOT
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find root from executable path.
|
||||||
|
path, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
// Very unlikely. Bail out if it happens.
|
||||||
|
panic("could not get executable path: " + err.Error())
|
||||||
|
}
|
||||||
|
root = filepath.Dir(filepath.Dir(path))
|
||||||
|
if isSourceDir(root) {
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: use the original directory from where it was built
|
||||||
|
// https://stackoverflow.com/a/32163888/559350
|
||||||
|
_, path, _, _ = runtime.Caller(0)
|
||||||
|
root = filepath.Dir(filepath.Dir(path))
|
||||||
|
if isSourceDir(root) {
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(os.Stderr, "error: could not autodetect root directory, set the TINYGOROOT environment variable to override")
|
||||||
|
os.Exit(1)
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
// isSourceDir returns true if the directory looks like a TinyGo source directory.
|
||||||
|
func isSourceDir(root string) bool {
|
||||||
|
_, err := os.Stat(filepath.Join(root, "src/runtime/internal/sys/zversion.go"))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, err = os.Stat(filepath.Join(root, "src/device/arm/arm.go"))
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getHomeDir() string {
|
||||||
|
u, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
panic("cannot get current user: " + err.Error())
|
||||||
|
}
|
||||||
|
if u.HomeDir == "" {
|
||||||
|
// This is very unlikely, so panic here.
|
||||||
|
// Not the nicest solution, however.
|
||||||
|
panic("could not find home directory")
|
||||||
|
}
|
||||||
|
return u.HomeDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// getGoroot returns an appropriate GOROOT from various sources. If it can't be
|
||||||
|
// found, it returns an empty string.
|
||||||
|
func getGoroot() string {
|
||||||
|
goroot := os.Getenv("GOROOT")
|
||||||
|
if goroot != "" {
|
||||||
|
// An explicitly set GOROOT always has preference.
|
||||||
|
return goroot
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for the location of the 'go' binary and base GOROOT on that.
|
||||||
|
binpath, err := exec.LookPath("go")
|
||||||
|
if err == nil {
|
||||||
|
binpath, err = filepath.EvalSymlinks(binpath)
|
||||||
|
if err == nil {
|
||||||
|
goroot := filepath.Dir(filepath.Dir(binpath))
|
||||||
|
if isGoroot(goroot) {
|
||||||
|
return goroot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check what GOROOT was at compile time.
|
||||||
|
if isGoroot(runtime.GOROOT()) {
|
||||||
|
return runtime.GOROOT()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for some standard locations, as a last resort.
|
||||||
|
var candidates []string
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "linux":
|
||||||
|
candidates = []string{
|
||||||
|
"/usr/local/go", // manually installed
|
||||||
|
"/usr/lib/go", // from the distribution
|
||||||
|
}
|
||||||
|
case "darwin":
|
||||||
|
candidates = []string{
|
||||||
|
"/usr/local/go", // manually installed
|
||||||
|
"/usr/local/opt/go/libexec", // from Homebrew
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, candidate := range candidates {
|
||||||
|
if isGoroot(candidate) {
|
||||||
|
return candidate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't find GOROOT...
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// isGoroot checks whether the given path looks like a GOROOT.
|
||||||
|
func isGoroot(goroot string) bool {
|
||||||
|
_, err := os.Stat(filepath.Join(goroot, "src", "runtime", "internal", "sys", "zversion.go"))
|
||||||
|
return err == nil
|
||||||
|
}
|
|
@ -9,6 +9,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -63,7 +65,7 @@ func Link(linker string, flags ...string) error {
|
||||||
cmd := exec.Command(linker, flags...)
|
cmd := exec.Command(linker, flags...)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
cmd.Dir = sourceDir()
|
cmd.Dir = goenv.Get("TINYGOROOT")
|
||||||
return cmd.Run()
|
return cmd.Run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Link invokes a linker with the given name and arguments.
|
// Link invokes a linker with the given name and arguments.
|
||||||
|
@ -20,6 +22,6 @@ func Link(linker string, flags ...string) error {
|
||||||
cmd := exec.Command(linker, flags...)
|
cmd := exec.Command(linker, flags...)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
cmd.Dir = sourceDir()
|
cmd.Dir = goenv.Get("TINYGOROOT")
|
||||||
return cmd.Run()
|
return cmd.Run()
|
||||||
}
|
}
|
||||||
|
|
14
main.go
14
main.go
|
@ -18,6 +18,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/compiler"
|
"github.com/tinygo-org/tinygo/compiler"
|
||||||
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
"github.com/tinygo-org/tinygo/interp"
|
"github.com/tinygo-org/tinygo/interp"
|
||||||
"github.com/tinygo-org/tinygo/loader"
|
"github.com/tinygo-org/tinygo/loader"
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
|
||||||
config.gc = spec.GC
|
config.gc = spec.GC
|
||||||
}
|
}
|
||||||
|
|
||||||
root := sourceDir()
|
root := goenv.Get("TINYGOROOT")
|
||||||
|
|
||||||
// Merge and adjust CFlags.
|
// Merge and adjust CFlags.
|
||||||
cflags := append([]string{}, config.cFlags...)
|
cflags := append([]string{}, config.cFlags...)
|
||||||
|
@ -84,7 +85,7 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
|
||||||
ldflags = append(ldflags, strings.Replace(flag, "{root}", root, -1))
|
ldflags = append(ldflags, strings.Replace(flag, "{root}", root, -1))
|
||||||
}
|
}
|
||||||
|
|
||||||
goroot := getGoroot()
|
goroot := goenv.Get("GOROOT")
|
||||||
if goroot == "" {
|
if goroot == "" {
|
||||||
return errors.New("cannot locate $GOROOT, please set it manually")
|
return errors.New("cannot locate $GOROOT, please set it manually")
|
||||||
}
|
}
|
||||||
|
@ -123,7 +124,7 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
|
||||||
VerifyIR: config.verifyIR,
|
VerifyIR: config.verifyIR,
|
||||||
TINYGOROOT: root,
|
TINYGOROOT: root,
|
||||||
GOROOT: goroot,
|
GOROOT: goroot,
|
||||||
GOPATH: getGopath(),
|
GOPATH: goenv.Get("GOPATH"),
|
||||||
BuildTags: tags,
|
BuildTags: tags,
|
||||||
TestConfig: config.testConfig,
|
TestConfig: config.testConfig,
|
||||||
}
|
}
|
||||||
|
@ -454,7 +455,7 @@ func Flash(pkgName, target, port string, config *BuildConfig) error {
|
||||||
cmd := exec.Command("/bin/sh", "-c", flashCmd)
|
cmd := exec.Command("/bin/sh", "-c", flashCmd)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
cmd.Dir = sourceDir()
|
cmd.Dir = goenv.Get("TINYGOROOT")
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &commandError{"failed to flash", tmppath, err}
|
return &commandError{"failed to flash", tmppath, err}
|
||||||
|
@ -719,7 +720,7 @@ func usage() {
|
||||||
fmt.Fprintln(os.Stderr, " test: test packages")
|
fmt.Fprintln(os.Stderr, " test: test packages")
|
||||||
fmt.Fprintln(os.Stderr, " flash: compile and flash to the device")
|
fmt.Fprintln(os.Stderr, " flash: compile and flash to the device")
|
||||||
fmt.Fprintln(os.Stderr, " gdb: run/flash and immediately enter GDB")
|
fmt.Fprintln(os.Stderr, " gdb: run/flash and immediately enter GDB")
|
||||||
fmt.Fprintln(os.Stderr, " clean: empty cache directory ("+cacheDir()+")")
|
fmt.Fprintln(os.Stderr, " clean: empty cache directory ("+goenv.Get("GOCACHE")+")")
|
||||||
fmt.Fprintln(os.Stderr, " help: print this help text")
|
fmt.Fprintln(os.Stderr, " help: print this help text")
|
||||||
fmt.Fprintln(os.Stderr, "\nflags:")
|
fmt.Fprintln(os.Stderr, "\nflags:")
|
||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
|
@ -890,8 +891,7 @@ func main() {
|
||||||
handleCompilerError(err)
|
handleCompilerError(err)
|
||||||
case "clean":
|
case "clean":
|
||||||
// remove cache directory
|
// remove cache directory
|
||||||
dir := cacheDir()
|
err := os.RemoveAll(goenv.Get("GOCACHE"))
|
||||||
err := os.RemoveAll(dir)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "cannot clean cache:", err)
|
fmt.Fprintln(os.Stderr, "cannot clean cache:", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
155
target.go
155
target.go
|
@ -8,17 +8,13 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/user"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
|
||||||
|
|
||||||
// TINYGOROOT is the path to the final location for checking tinygo files. If
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
// unset (by a -X ldflag), then sourceDir() will fallback to the original build
|
)
|
||||||
// directory.
|
|
||||||
var TINYGOROOT string
|
|
||||||
|
|
||||||
// Target specification for a given target. Used for bare metal targets.
|
// Target specification for a given target. Used for bare metal targets.
|
||||||
//
|
//
|
||||||
|
@ -147,7 +143,7 @@ func (spec *TargetSpec) loadFromGivenStr(str string) error {
|
||||||
if strings.HasSuffix(str, ".json") {
|
if strings.HasSuffix(str, ".json") {
|
||||||
path, _ = filepath.Abs(str)
|
path, _ = filepath.Abs(str)
|
||||||
} else {
|
} else {
|
||||||
path = filepath.Join(sourceDir(), "targets", strings.ToLower(str)+".json")
|
path = filepath.Join(goenv.Get("TINYGOROOT"), "targets", strings.ToLower(str)+".json")
|
||||||
}
|
}
|
||||||
fp, err := os.Open(path)
|
fp, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -186,14 +182,8 @@ func LoadTarget(target string) (*TargetSpec, error) {
|
||||||
if target == "" {
|
if target == "" {
|
||||||
// Configure based on GOOS/GOARCH environment variables (falling back to
|
// Configure based on GOOS/GOARCH environment variables (falling back to
|
||||||
// runtime.GOOS/runtime.GOARCH), and generate a LLVM target based on it.
|
// runtime.GOOS/runtime.GOARCH), and generate a LLVM target based on it.
|
||||||
goos := os.Getenv("GOOS")
|
goos := goenv.Get("GOOS")
|
||||||
if goos == "" {
|
goarch := goenv.Get("GOARCH")
|
||||||
goos = runtime.GOOS
|
|
||||||
}
|
|
||||||
goarch := os.Getenv("GOARCH")
|
|
||||||
if goarch == "" {
|
|
||||||
goarch = runtime.GOARCH
|
|
||||||
}
|
|
||||||
llvmos := goos
|
llvmos := goos
|
||||||
llvmarch := map[string]string{
|
llvmarch := map[string]string{
|
||||||
"386": "i386",
|
"386": "i386",
|
||||||
|
@ -315,141 +305,6 @@ func (spec *TargetSpec) OpenOCDConfiguration() (args []string, err error) {
|
||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the TINYGOROOT, or exit with an error.
|
|
||||||
func sourceDir() string {
|
|
||||||
// Use $TINYGOROOT as root, if available.
|
|
||||||
root := os.Getenv("TINYGOROOT")
|
|
||||||
if root != "" {
|
|
||||||
if !isSourceDir(root) {
|
|
||||||
fmt.Fprintln(os.Stderr, "error: $TINYGOROOT was not set to the correct root")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
if TINYGOROOT != "" {
|
|
||||||
if !isSourceDir(TINYGOROOT) {
|
|
||||||
fmt.Fprintln(os.Stderr, "error: TINYGOROOT was not set to the correct root")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
return TINYGOROOT
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find root from executable path.
|
|
||||||
path, err := os.Executable()
|
|
||||||
if err != nil {
|
|
||||||
// Very unlikely. Bail out if it happens.
|
|
||||||
panic("could not get executable path: " + err.Error())
|
|
||||||
}
|
|
||||||
root = filepath.Dir(filepath.Dir(path))
|
|
||||||
if isSourceDir(root) {
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback: use the original directory from where it was built
|
|
||||||
// https://stackoverflow.com/a/32163888/559350
|
|
||||||
_, path, _, _ = runtime.Caller(0)
|
|
||||||
root = filepath.Dir(path)
|
|
||||||
if isSourceDir(root) {
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintln(os.Stderr, "error: could not autodetect root directory, set the TINYGOROOT environment variable to override")
|
|
||||||
os.Exit(1)
|
|
||||||
panic("unreachable")
|
|
||||||
}
|
|
||||||
|
|
||||||
// isSourceDir returns true if the directory looks like a TinyGo source directory.
|
|
||||||
func isSourceDir(root string) bool {
|
|
||||||
_, err := os.Stat(filepath.Join(root, "src/runtime/internal/sys/zversion.go"))
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
_, err = os.Stat(filepath.Join(root, "src/device/arm/arm.go"))
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getGopath() string {
|
|
||||||
gopath := os.Getenv("GOPATH")
|
|
||||||
if gopath != "" {
|
|
||||||
return gopath
|
|
||||||
}
|
|
||||||
|
|
||||||
// fallback
|
|
||||||
home := getHomeDir()
|
|
||||||
return filepath.Join(home, "go")
|
|
||||||
}
|
|
||||||
|
|
||||||
func getHomeDir() string {
|
|
||||||
u, err := user.Current()
|
|
||||||
if err != nil {
|
|
||||||
panic("cannot get current user: " + err.Error())
|
|
||||||
}
|
|
||||||
if u.HomeDir == "" {
|
|
||||||
// This is very unlikely, so panic here.
|
|
||||||
// Not the nicest solution, however.
|
|
||||||
panic("could not find home directory")
|
|
||||||
}
|
|
||||||
return u.HomeDir
|
|
||||||
}
|
|
||||||
|
|
||||||
// getGoroot returns an appropriate GOROOT from various sources. If it can't be
|
|
||||||
// found, it returns an empty string.
|
|
||||||
func getGoroot() string {
|
|
||||||
goroot := os.Getenv("GOROOT")
|
|
||||||
if goroot != "" {
|
|
||||||
// An explicitly set GOROOT always has preference.
|
|
||||||
return goroot
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for the location of the 'go' binary and base GOROOT on that.
|
|
||||||
binpath, err := exec.LookPath("go")
|
|
||||||
if err == nil {
|
|
||||||
binpath, err = filepath.EvalSymlinks(binpath)
|
|
||||||
if err == nil {
|
|
||||||
goroot := filepath.Dir(filepath.Dir(binpath))
|
|
||||||
if isGoroot(goroot) {
|
|
||||||
return goroot
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check what GOROOT was at compile time.
|
|
||||||
if isGoroot(runtime.GOROOT()) {
|
|
||||||
return runtime.GOROOT()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for some standard locations, as a last resort.
|
|
||||||
var candidates []string
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "linux":
|
|
||||||
candidates = []string{
|
|
||||||
"/usr/local/go", // manually installed
|
|
||||||
"/usr/lib/go", // from the distribution
|
|
||||||
}
|
|
||||||
case "darwin":
|
|
||||||
candidates = []string{
|
|
||||||
"/usr/local/go", // manually installed
|
|
||||||
"/usr/local/opt/go/libexec", // from Homebrew
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, candidate := range candidates {
|
|
||||||
if isGoroot(candidate) {
|
|
||||||
return candidate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can't find GOROOT...
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// isGoroot checks whether the given path looks like a GOROOT.
|
|
||||||
func isGoroot(goroot string) bool {
|
|
||||||
_, err := os.Stat(filepath.Join(goroot, "src", "runtime", "internal", "sys", "zversion.go"))
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getGorootVersion returns the major and minor version for a given GOROOT path.
|
// getGorootVersion returns the major and minor version for a given GOROOT path.
|
||||||
// If the goroot cannot be determined, (0, 0) is returned.
|
// If the goroot cannot be determined, (0, 0) is returned.
|
||||||
func getGorootVersion(goroot string) (major, minor int, err error) {
|
func getGorootVersion(goroot string) (major, minor int, err error) {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче