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