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