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