aboutsummaryrefslogtreecommitdiffhomepage
path: root/target.go
blob: 8f7a44cc26462e528eb676e039b0180b3a3667cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package main

import (
	"encoding/json"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

// Target specification for a given target. Used for bare metal targets.
//
// The target specification is mostly inspired by Rust:
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.TargetOptions.html
// https://github.com/shepmaster/rust-arduino-blink-led-no-core-with-cargo/blob/master/blink/arduino.json
type TargetSpec struct {
	Triple      string   `json:"llvm-target"`
	BuildTags   []string `json:"build-tags"`
	Linker      string   `json:"linker"`
	PreLinkArgs []string `json:"pre-link-args"`
	Objcopy     string   `json:"objcopy"`
	Flasher     string   `json:"flash"`
}

// Load a target specification
func LoadTarget(target string) (*TargetSpec, error) {
	spec := &TargetSpec{
		Triple:      target,
		BuildTags:   []string{runtime.GOOS, runtime.GOARCH},
		Linker:      "cc",
		PreLinkArgs: []string{"-no-pie"}, // WARNING: clang < 5.0 requires -nopie
		Objcopy:     "objcopy",
	}

	// See whether there is a target specification for this target (e.g.
	// Arduino).
	path := filepath.Join(sourceDir(), "targets", strings.ToLower(target)+".json")
	if fp, err := os.Open(path); err == nil {
		defer fp.Close()
		err := json.NewDecoder(fp).Decode(spec)
		if err != nil {
			return nil, err
		}
	} else if !os.IsNotExist(err) {
		// Expected a 'file not found' error, got something else.
		return nil, err
	} else {
		// No target spec available. This is fine.
	}

	return spec, nil
}

// Return the source directory of this package, or "." when it cannot be
// recovered.
func sourceDir() string {
	// https://stackoverflow.com/a/32163888/559350
	_, path, _, _ := runtime.Caller(0)
	return filepath.Dir(path)
}

func getGopath() string {
	gopath := os.Getenv("GOPATH")
	if gopath != "" {
		return gopath
	}

	// fallback
	var home string
	if runtime.GOOS == "windows" {
		home = os.Getenv("USERPROFILE")
	} else {
		home = os.Getenv("HOME")
	}
	if home == "" {
		// This is very unlikely, so panic here.
		// Not the nicest solution, however.
		panic("no $HOME or %USERPROFILE% found")
	}
	return filepath.Join(home, "go")
}