target.go raw
1 package compileopts
2
3 import (
4 "fmt"
5 "runtime"
6 "strings"
7 )
8
9 // TargetSpec is the target specification for a given target.
10 type TargetSpec struct {
11 Triple string `json:"llvm-target,omitempty"`
12 CPU string `json:"cpu,omitempty"`
13 ABI string `json:"target-abi,omitempty"`
14 Features string `json:"features,omitempty"`
15 GOOS string `json:"goos,omitempty"`
16 GOARCH string `json:"goarch,omitempty"`
17 BuildTags []string `json:"build-tags,omitempty"`
18 BuildMode string `json:"buildmode,omitempty"`
19 Scheduler string `json:"scheduler,omitempty"`
20 Linker string `json:"linker,omitempty"`
21 RTLib string `json:"rtlib,omitempty"`
22 Libc string `json:"libc,omitempty"`
23 DefaultStackSize uint64 `json:"default-stack-size,omitempty"`
24 CFlags []string `json:"cflags,omitempty"`
25 LDFlags []string `json:"ldflags,omitempty"`
26 LinkerScript string `json:"linkerscript,omitempty"`
27 ExtraFiles []string `json:"extra-files,omitempty"`
28 BinaryFormat string `json:"binary-format,omitempty"`
29 CodeModel string `json:"code-model,omitempty"`
30 RelocationModel string `json:"relocation-model,omitempty"`
31 Emulator string `json:"emulator,omitempty"`
32 }
33
34 // LoadTarget loads a target specification from options.
35 func LoadTarget(options *Options) (*TargetSpec, error) {
36 // Parse compound target like "js/wasm" into GOOS/GOARCH.
37 if strings.Contains(options.Target, "/") {
38 parts := strings.SplitN(options.Target, "/", 2)
39 options.GOOS = parts[0]
40 options.GOARCH = parts[1]
41 options.Target = ""
42 }
43 if options.Target == "wasm" {
44 options.GOOS = "js"
45 options.GOARCH = "wasm"
46 options.Target = ""
47 }
48 return defaultTarget(options)
49 }
50
51 // defaultTarget synthesizes a TargetSpec from GOOS/GOARCH.
52 func defaultTarget(options *Options) (*TargetSpec, error) {
53 spec := TargetSpec{
54 GOOS: options.GOOS,
55 GOARCH: options.GOARCH,
56 BuildTags: []string{options.GOOS, options.GOARCH},
57 Linker: "cc",
58 DefaultStackSize: 1024 * 64, // 64kB
59 }
60
61 var llvmarch string
62 switch options.GOARCH {
63 case "amd64":
64 llvmarch = "x86_64"
65 spec.CPU = "x86-64"
66 spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
67 case "arm64":
68 spec.CPU = "generic"
69 llvmarch = "aarch64"
70 if options.GOOS == "darwin" {
71 spec.Features = "+ete,+fp-armv8,+neon,+trbe,+v8a"
72 llvmarch = "arm64"
73 } else {
74 spec.Features = "+ete,+fp-armv8,+neon,+trbe,+v8a,-fmv,-outline-atomics"
75 }
76 case "wasm":
77 if options.GOOS != "js" {
78 return nil, fmt.Errorf("GOARCH=wasm requires GOOS=js")
79 }
80 llvmarch = "wasm32"
81 spec.CPU = "generic"
82 spec.Features = "+mutable-globals,+sign-ext"
83 default:
84 return nil, fmt.Errorf("unsupported GOARCH=%s (moxie supports amd64, arm64, wasm)", options.GOARCH)
85 }
86
87 // Configure target based on GOOS.
88 llvmos := options.GOOS
89 llvmvendor := "unknown"
90 switch options.GOOS {
91 case "darwin":
92 platformVersion := "10.12.0"
93 if options.GOARCH == "arm64" {
94 platformVersion = "11.0.0"
95 }
96 llvmvendor = "apple"
97 spec.Scheduler = "none" // moxie: no goroutines
98 spec.Linker = "ld.lld"
99 spec.Libc = "darwin-libSystem"
100 llvmos = "macosx" + platformVersion
101 spec.LDFlags = append(spec.LDFlags,
102 "-flavor", "darwin",
103 "-dead_strip",
104 "-arch", llvmarch,
105 "-platform_version", "macos", platformVersion, platformVersion,
106 )
107 spec.ExtraFiles = append(spec.ExtraFiles,
108 "src/runtime/os_darwin.c",
109 "src/runtime/runtime_unix.c",
110 "src/runtime/secalloc.c",
111 "src/runtime/signal.c",
112 "src/runtime/spawn_unix.c",
113 "src/runtime/futex_darwin.c")
114 case "linux":
115 spec.Scheduler = "none" // moxie: no goroutines
116 spec.Linker = "ld.lld"
117 spec.RTLib = "compiler-rt"
118 spec.Libc = "musl"
119 spec.LDFlags = append(spec.LDFlags, "--gc-sections")
120 if options.GOARCH == "arm64" {
121 spec.CFlags = append(spec.CFlags, "-mno-outline-atomics")
122 }
123 spec.ExtraFiles = append(spec.ExtraFiles,
124 "src/runtime/runtime_unix.c",
125 "src/runtime/secalloc.c",
126 "src/runtime/signal.c",
127 "src/runtime/spawn_unix.c",
128 "src/runtime/futex_linux.c",
129 "src/runtime/ffi_linux.c")
130 case "js":
131 spec.Scheduler = "none" // moxie: no goroutines
132 spec.Linker = "wasm-ld"
133 spec.BuildTags = append(spec.BuildTags, "moxie.wasm", "moxie.unicore")
134 spec.LDFlags = append(spec.LDFlags,
135 "--export-dynamic",
136 "--allow-undefined",
137 "--gc-sections",
138 )
139 default:
140 return nil, fmt.Errorf("unsupported GOOS=%s (moxie supports linux, darwin, js)", options.GOOS)
141 }
142
143 // Target triple: arch-vendor-os[-environment]
144 spec.Triple = llvmarch + "-" + llvmvendor + "-" + llvmos
145 if options.GOOS == "linux" {
146 spec.Triple += "-musleabihf"
147 }
148
149 // Assembly files (not for WASM).
150 if options.GOARCH != "wasm" {
151 spec.ExtraFiles = append(spec.ExtraFiles,
152 "src/runtime/asm_"+options.GOARCH+".S")
153 if spec.Scheduler == "tasks" {
154 spec.ExtraFiles = append(spec.ExtraFiles,
155 "src/internal/task/task_stack_"+options.GOARCH+".S")
156 }
157 }
158
159 // Cross-compilation emulator.
160 if options.GOARCH != runtime.GOARCH && options.GOOS == "linux" {
161 switch options.GOARCH {
162 case "amd64":
163 spec.Emulator = "qemu-x86_64 {}"
164 case "arm64":
165 spec.Emulator = "qemu-aarch64 {}"
166 }
167 }
168
169 return &spec, nil
170 }
171
172 // LookupGDB looks up a gdb executable. Returns empty string if not needed.
173 func (spec *TargetSpec) LookupGDB() string {
174 return ""
175 }
176
177 // GetTargetSpecs returns available target specs. Moxie has no JSON target files.
178 func GetTargetSpecs() map[string]*TargetSpec {
179 goos := []string{"linux", "darwin"}
180 goarch := []string{"amd64", "arm64"}
181 specs := make(map[string]*TargetSpec)
182 for _, os := range goos {
183 for _, arch := range goarch {
184 name := os + "/" + arch
185 t, err := defaultTarget(&Options{GOOS: os, GOARCH: arch})
186 if err == nil {
187 specs[name] = t
188 }
189 }
190 }
191 // Add js/wasm.
192 t, err := defaultTarget(&Options{GOOS: "js", GOARCH: "wasm"})
193 if err == nil {
194 specs["js/wasm"] = t
195 }
196 return specs
197 }
198
199 // Triple returns a cleaned version for display.
200 func (spec *TargetSpec) TripleForDisplay() string {
201 return strings.TrimSpace(spec.Triple)
202 }
203