@@ -3,6 +3,7 @@ package main
33import (
44 "encoding/json"
55 "errors"
6+ "fmt"
67 "io"
78 "os"
89 "os/user"
@@ -235,12 +236,50 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
235236 return & spec , nil
236237}
237238
238- // Return the source directory of this package, or "." when it cannot be
239- // recovered.
239+ // Return the TINYGOROOT, or exit with an error.
240240func sourceDir () string {
241+ // Use $TINYGOROOT as root, if available.
242+ root := os .Getenv ("TINYGOROOT" )
243+ if root != "" {
244+ if ! isSourceDir (root ) {
245+ fmt .Fprintln (os .Stderr , "error: $TINYGOROOT was not set to the correct root" )
246+ os .Exit (1 )
247+ }
248+ return root
249+ }
250+
251+ // Find root from executable path.
252+ path , err := os .Executable ()
253+ if err != nil {
254+ // Very unlikely. Bail out if it happens.
255+ panic ("could not get executable path: " + err .Error ())
256+ }
257+ root = filepath .Dir (filepath .Dir (path ))
258+ if isSourceDir (root ) {
259+ return root
260+ }
261+
262+ // Fallback: use the original directory from where it was built
241263 // https://stackoverflow.com/a/32163888/559350
242- _ , path , _ , _ := runtime .Caller (0 )
243- return filepath .Dir (path )
264+ _ , path , _ , _ = runtime .Caller (0 )
265+ root = filepath .Dir (path )
266+ if isSourceDir (root ) {
267+ return root
268+ }
269+
270+ fmt .Fprintln (os .Stderr , "error: could not autodetect root directory, set the TINYGOROOT environment variable to override" )
271+ os .Exit (1 )
272+ panic ("unreachable" )
273+ }
274+
275+ // isSourceDir returns true if the directory looks like a TinyGo source directory.
276+ func isSourceDir (root string ) bool {
277+ _ , err := os .Stat (filepath .Join (root , "src/runtime/internal/sys/zversion.go" ))
278+ if err != nil {
279+ return false
280+ }
281+ _ , err = os .Stat (filepath .Join (root , "src/device/arm/arm.go" ))
282+ return err == nil
244283}
245284
246285func getGopath () string {
0 commit comments