all: refactor compile options

Move most of the logic of determining which compiler configuration to
use (such as GOOS/GOARCH, build tags, whether to include debug symbols,
panic strategy, etc.) into the compileopts package. This makes it a
single source of truth for anything related to compiler configuration.

It has a few advantages:

  * The compile configuration is independent of the compiler package.
    This makes it possible to move optimization passes out of the
    compiler, as they don't rely on compiler.Config anymore.
  * There is only one place to look if an incorrect compile option is
    used.
  * The compileopts provides some resistance against unintentionally
    picking the wrong option, such as with c.selectGC() vs c.GC() in the
    compiler.
  * It is now a lot easier to change compile options, as most options
    are getters now.
This commit is contained in:
Ayke van Laethem
2019-10-31 17:39:22 +01:00
committed by Ron Evans
parent 59cc901340
commit 3b0ed63c29
10 changed files with 181 additions and 146 deletions
+116 -19
View File
@@ -2,27 +2,124 @@
// binary.
package compileopts
import (
"fmt"
"strings"
"github.com/tinygo-org/tinygo/goenv"
)
// Config keeps all configuration affecting the build in a single struct.
type Config struct {
Triple string // LLVM target triple, e.g. x86_64-unknown-linux-gnu (empty string means default)
CPU string // LLVM CPU name, e.g. atmega328p (empty string means default)
Features []string // LLVM CPU features
GOOS string //
GOARCH string //
GC string // garbage collection strategy
Scheduler string // scheduler implementation ("coroutines" or "tasks")
PanicStrategy string // panic strategy ("print" or "trap")
CFlags []string // cflags to pass to cgo
LDFlags []string // ldflags to pass to cgo
ClangHeaders string // Clang built-in header include path
DumpSSA bool // dump Go SSA, for compiler debugging
VerifyIR bool // run extra checks on the IR
Debug bool // add debug symbols for gdb
GOROOT string // GOROOT
TINYGOROOT string // GOROOT for TinyGo
GOPATH string // GOPATH, like `go env GOPATH`
BuildTags []string // build tags for TinyGo (empty means {Config.GOOS/Config.GOARCH})
TestConfig TestConfig
Options *Options
Target *TargetSpec
GoMinorVersion int
ClangHeaders string // Clang built-in header include path
TestConfig TestConfig
}
// Triple returns the LLVM target triple, like armv6m-none-eabi.
func (c *Config) Triple() string {
return c.Target.Triple
}
// CPU returns the LLVM CPU name, like atmega328p or arm7tdmi. It may return an
// empty string if the CPU name is not known.
func (c *Config) CPU() string {
return c.Target.CPU
}
// Features returns a list of features this CPU supports. For example, for a
// RISC-V processor, that could be ["+a", "+c", "+m"]. For many targets, an
// empty list will be returned.
func (c *Config) Features() []string {
return c.Target.Features
}
// GOOS returns the GOOS of the target. This might not always be the actual OS:
// for example, bare-metal targets will usually pretend to be linux to get the
// standard library to compile.
func (c *Config) GOOS() string {
return c.Target.GOOS
}
// GOARCH returns the GOARCH of the target. This might not always be the actual
// archtecture: for example, the AVR target is not supported by the Go standard
// library so such targets will usually pretend to be linux/arm.
func (c *Config) GOARCH() string {
return c.Target.GOARCH
}
// BuildTags returns the complete list of build tags used during this build.
func (c *Config) BuildTags() []string {
tags := append(c.Target.BuildTags, []string{"tinygo", "gc." + c.GC(), "scheduler." + c.Scheduler()}...)
for i := 1; i <= c.GoMinorVersion; i++ {
tags = append(tags, fmt.Sprintf("go1.%d", i))
}
if extraTags := strings.Fields(c.Options.Tags); len(extraTags) != 0 {
tags = append(tags, extraTags...)
}
return tags
}
// GC returns the garbage collection strategy in use on this platform. Valid
// values are "none", "leaking", and "conservative".
func (c *Config) GC() string {
if c.Options.GC != "" {
return c.Options.GC
}
if c.Target.GC != "" {
return c.Target.GC
}
return "conservative"
}
// Scheduler returns the scheduler implementation. Valid values are "coroutines"
// and "tasks".
func (c *Config) Scheduler() string {
if c.Options.Scheduler != "" {
return c.Options.Scheduler
}
if c.Target.Scheduler != "" {
return c.Target.Scheduler
}
// Fall back to coroutines, which are supported everywhere.
return "coroutines"
}
// PanicStrategy returns the panic strategy selected for this target. Valid
// values are "print" (print the panic value, then exit) or "trap" (issue a trap
// instruction).
func (c *Config) PanicStrategy() string {
return c.Options.PanicStrategy
}
// CFlags returns the flags to pass to the C compiler. This is necessary for CGo
// preprocessing.
func (c *Config) CFlags() []string {
cflags := append([]string{}, c.Options.CFlags...)
for _, flag := range c.Target.CFlags {
cflags = append(cflags, strings.Replace(flag, "{root}", goenv.Get("TINYGOROOT"), -1))
}
return cflags
}
// DumpSSA returns whether to dump Go SSA while compiling (-dumpssa flag). Only
// enable this for debugging.
func (c *Config) DumpSSA() bool {
return c.Options.DumpSSA
}
// VerifyIR returns whether to run extra checks on the IR. This is normally
// disabled but enabled during testing.
func (c *Config) VerifyIR() bool {
return c.Options.VerifyIR
}
// Debug returns whether to add debug symbols to the IR, for debugging with GDB
// and similar.
func (c *Config) Debug() bool {
return c.Options.Debug
}
type TestConfig struct {