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