config.go raw
1 // Package compileopts contains the configuration for a single to-be-built binary.
2 package compileopts
3
4 import (
5 "fmt"
6 "path/filepath"
7 "strconv"
8 "strings"
9
10 "moxie/goenv"
11 )
12
13 var libVersions = map[string]int{
14 "musl": 3,
15 "bdwgc": 2,
16 }
17
18 // Config keeps all configuration affecting the build in a single struct.
19 type Config struct {
20 Options *Options
21 Target *TargetSpec
22 GoMinorVersion int
23 TestConfig TestConfig
24 }
25
26 func (c *Config) Triple() string { return c.Target.Triple }
27 func (c *Config) CPU() string { return c.Target.CPU }
28 func (c *Config) ABI() string { return c.Target.ABI }
29 func (c *Config) GOOS() string { return c.Target.GOOS }
30 func (c *Config) GOARCH() string { return c.Target.GOARCH }
31 func (c *Config) DumpSSA() bool { return c.Options.DumpSSA }
32 func (c *Config) VerifyIR() bool { return c.Options.VerifyIR }
33 func (c *Config) Debug() bool { return c.Options.Debug }
34 func (c *Config) ExtraFiles() []string { return c.Target.ExtraFiles }
35
36 func (c *Config) BuildMode() string {
37 if c.Options.BuildMode != "" {
38 return c.Options.BuildMode
39 }
40 if c.Target.BuildMode != "" {
41 return c.Target.BuildMode
42 }
43 return "default"
44 }
45
46 func (c *Config) Features() string {
47 if c.Target.Features == "" {
48 return c.Options.LLVMFeatures
49 }
50 if c.Options.LLVMFeatures == "" {
51 return c.Target.Features
52 }
53 return c.Target.Features + "," + c.Options.LLVMFeatures
54 }
55
56 // BuildTags returns the complete list of build tags used during this build.
57 func (c *Config) BuildTags() []string {
58 tags := append([]string(nil), c.Target.BuildTags...)
59 tags = append(tags,
60 "moxie",
61 "purego",
62 "osusergo",
63 "math_big_pure_go",
64 "gc."+c.GC(),
65 "scheduler."+c.Scheduler(),
66 "moxie.unicore", // always single-core cooperative
67 )
68 for i := 1; i <= c.GoMinorVersion; i++ {
69 tags = append(tags, fmt.Sprintf("go1.%d", i))
70 }
71 tags = append(tags, c.Options.Tags...)
72 return tags
73 }
74
75 func (c *Config) GC() string {
76 if c.Options.GC != "" {
77 return c.Options.GC
78 }
79 if c.Target.GC != "" {
80 return c.Target.GC
81 }
82 return "conservative"
83 }
84
85 func (c *Config) NeedsStackObjects() bool {
86 return false
87 }
88
89 // Scheduler returns the scheduler implementation. Moxie uses "none" (no goroutines).
90 func (c *Config) Scheduler() string {
91 if c.Options.Scheduler != "" {
92 return c.Options.Scheduler
93 }
94 if c.Target.Scheduler != "" {
95 return c.Target.Scheduler
96 }
97 return "none"
98 }
99
100 func (c *Config) OptLevel() (level string, speedLevel, sizeLevel int) {
101 switch c.Options.Opt {
102 case "none", "0":
103 return "O0", 0, 0
104 case "1":
105 return "O1", 1, 0
106 case "2":
107 return "O2", 2, 0
108 case "s":
109 return "Os", 2, 1
110 case "z":
111 return "Oz", 2, 2
112 default:
113 panic("unknown optimization level: -opt=" + c.Options.Opt)
114 }
115 }
116
117 func (c *Config) PanicStrategy() string { return c.Options.PanicStrategy }
118
119 func (c *Config) StackSize() uint64 {
120 if c.Options.StackSize != 0 {
121 return c.Options.StackSize
122 }
123 return c.Target.DefaultStackSize
124 }
125
126 func (c *Config) MaxStackAlloc() uint64 {
127 if c.StackSize() >= 16*1024 {
128 return 1024
129 }
130 return 256
131 }
132
133 func CanonicalArchName(triple string) string {
134 arch := strings.Split(triple, "-")[0]
135 if arch == "arm64" {
136 return "aarch64"
137 }
138 return arch
139 }
140
141 func MuslArchitecture(triple string) string {
142 return CanonicalArchName(triple)
143 }
144
145 func (c *Config) LibraryPath(name string) string {
146 archname := c.Triple()
147 if c.CPU() != "" {
148 archname += "-" + c.CPU()
149 }
150 if c.ABI() != "" {
151 archname += "-" + c.ABI()
152 }
153 if name == "bdwgc" {
154 archname += "-" + c.Target.Libc
155 }
156 if v, ok := libVersions[name]; ok {
157 archname += "-v" + strconv.Itoa(v)
158 }
159 return filepath.Join(goenv.Get("GOCACHE"), name+"-"+archname)
160 }
161
162 func (c *Config) DefaultBinaryExtension() string {
163 parts := strings.Split(c.Triple(), "-")
164 if parts[0] == "wasm32" {
165 return ".wasm"
166 }
167 return ""
168 }
169
170 // CFlags returns the flags to pass to the C compiler.
171 func (c *Config) CFlags() []string {
172 var cflags []string
173 for _, flag := range c.Target.CFlags {
174 cflags = append(cflags, strings.ReplaceAll(flag, "{root}", goenv.Get("MOXIEROOT")))
175 }
176 resourceDir := goenv.ClangResourceDir()
177 if resourceDir != "" {
178 cflags = append(cflags, "-resource-dir="+resourceDir)
179 }
180 cflags = append(cflags, c.LibcCFlags()...)
181 cflags = append(cflags, "-gdwarf-4")
182 cflags = append(cflags, "-O"+c.Options.Opt)
183 cflags = append(cflags, "--target="+c.Triple())
184 if c.Target.CPU != "" {
185 if c.GOARCH() == "amd64" {
186 cflags = append(cflags, "-march="+c.Target.CPU)
187 } else {
188 cflags = append(cflags, "-mcpu="+c.Target.CPU)
189 }
190 }
191 if c.ABI() != "" {
192 cflags = append(cflags, "-mabi="+c.ABI())
193 }
194 return cflags
195 }
196
197 func (c *Config) LibcCFlags() []string {
198 switch c.Target.Libc {
199 case "darwin-libSystem":
200 root := goenv.Get("MOXIEROOT")
201 return []string{
202 "-nostdlibinc",
203 "-isystem", filepath.Join(root, "lib/macos-minimal-sdk/src/usr/include"),
204 }
205 case "musl":
206 root := goenv.Get("MOXIEROOT")
207 path := c.LibraryPath("musl")
208 arch := MuslArchitecture(c.Triple())
209 return []string{
210 "-nostdlibinc",
211 "-isystem", filepath.Join(path, "include"),
212 "-isystem", filepath.Join(root, "lib", "musl", "arch", arch),
213 "-isystem", filepath.Join(root, "lib", "musl", "arch", "generic"),
214 "-isystem", filepath.Join(root, "lib", "musl", "include"),
215 }
216 case "":
217 return nil
218 default:
219 panic("unknown libc: " + c.Target.Libc)
220 }
221 }
222
223 func (c *Config) LDFlags() []string {
224 root := goenv.Get("MOXIEROOT")
225 var ldflags []string
226 for _, flag := range c.Target.LDFlags {
227 ldflags = append(ldflags, strings.ReplaceAll(flag, "{root}", root))
228 }
229 ldflags = append(ldflags, "-L", root)
230 if c.Target.LinkerScript != "" {
231 ldflags = append(ldflags, "-T", c.Target.LinkerScript)
232 }
233 ldflags = append(ldflags, c.Options.ExtLDFlags...)
234 return ldflags
235 }
236
237 func (c *Config) CodeModel() string {
238 if c.Target.CodeModel != "" {
239 return c.Target.CodeModel
240 }
241 return "default"
242 }
243
244 func (c *Config) RelocationModel() string {
245 if c.Target.RelocationModel != "" {
246 return c.Target.RelocationModel
247 }
248 return "static"
249 }
250
251 // Emulator returns the emulator command, or empty if none configured.
252 func (c *Config) Emulator() string {
253 return c.Target.Emulator
254 }
255
256 type TestConfig struct {
257 CompileTestBinary bool
258 CompileOnly bool
259 Verbose bool
260 Short bool
261 RunRegexp string
262 SkipRegexp string
263 Count *int
264 BenchRegexp string
265 BenchTime string
266 BenchMem bool
267 Shuffle string
268 }
269