mirror of https://github.com/tinygo-org/tinygo.git
wasmstm32webassemblymicrocontrollerarmavrspiwasiadafruitarduinocircuitplayground-expressgpioi2cllvmmicrobitnrf51nrf52nrf52840samd21tinygo
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
539 lines
19 KiB
539 lines
19 KiB
package compileopts
|
|
|
|
// This file loads a target specification from a JSON file.
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"reflect"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/tinygo-org/tinygo/goenv"
|
|
)
|
|
|
|
// Target specification for a given target. Used for bare metal targets.
|
|
//
|
|
// The target specification is mostly inspired by Rust:
|
|
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.TargetOptions.html
|
|
// https://github.com/shepmaster/rust-arduino-blink-led-no-core-with-cargo/blob/master/blink/arduino.json
|
|
type TargetSpec struct {
|
|
Inherits []string `json:"inherits,omitempty"`
|
|
Triple string `json:"llvm-target,omitempty"`
|
|
CPU string `json:"cpu,omitempty"`
|
|
ABI string `json:"target-abi,omitempty"` // roughly equivalent to -mabi= flag
|
|
Features string `json:"features,omitempty"`
|
|
GOOS string `json:"goos,omitempty"`
|
|
GOARCH string `json:"goarch,omitempty"`
|
|
SoftFloat bool // used for non-baremetal systems (GOMIPS=softfloat etc)
|
|
BuildTags []string `json:"build-tags,omitempty"`
|
|
GC string `json:"gc,omitempty"`
|
|
Scheduler string `json:"scheduler,omitempty"`
|
|
Serial string `json:"serial,omitempty"` // which serial output to use (uart, usb, none)
|
|
Linker string `json:"linker,omitempty"`
|
|
RTLib string `json:"rtlib,omitempty"` // compiler runtime library (libgcc, compiler-rt)
|
|
Libc string `json:"libc,omitempty"`
|
|
AutoStackSize *bool `json:"automatic-stack-size,omitempty"` // Determine stack size automatically at compile time.
|
|
DefaultStackSize uint64 `json:"default-stack-size,omitempty"` // Default stack size if the size couldn't be determined at compile time.
|
|
CFlags []string `json:"cflags,omitempty"`
|
|
LDFlags []string `json:"ldflags,omitempty"`
|
|
LinkerScript string `json:"linkerscript,omitempty"`
|
|
ExtraFiles []string `json:"extra-files,omitempty"`
|
|
RP2040BootPatch *bool `json:"rp2040-boot-patch,omitempty"` // Patch RP2040 2nd stage bootloader checksum
|
|
Emulator string `json:"emulator,omitempty"`
|
|
FlashCommand string `json:"flash-command,omitempty"`
|
|
GDB []string `json:"gdb,omitempty"`
|
|
PortReset string `json:"flash-1200-bps-reset,omitempty"`
|
|
SerialPort []string `json:"serial-port,omitempty"` // serial port IDs in the form "vid:pid"
|
|
FlashMethod string `json:"flash-method,omitempty"`
|
|
FlashVolume []string `json:"msd-volume-name,omitempty"`
|
|
FlashFilename string `json:"msd-firmware-name,omitempty"`
|
|
UF2FamilyID string `json:"uf2-family-id,omitempty"`
|
|
BinaryFormat string `json:"binary-format,omitempty"`
|
|
OpenOCDInterface string `json:"openocd-interface,omitempty"`
|
|
OpenOCDTarget string `json:"openocd-target,omitempty"`
|
|
OpenOCDTransport string `json:"openocd-transport,omitempty"`
|
|
OpenOCDCommands []string `json:"openocd-commands,omitempty"`
|
|
OpenOCDVerify *bool `json:"openocd-verify,omitempty"` // enable verify when flashing with openocd
|
|
JLinkDevice string `json:"jlink-device,omitempty"`
|
|
CodeModel string `json:"code-model,omitempty"`
|
|
RelocationModel string `json:"relocation-model,omitempty"`
|
|
WITPackage string `json:"wit-package,omitempty"`
|
|
WITWorld string `json:"wit-world,omitempty"`
|
|
}
|
|
|
|
// overrideProperties overrides all properties that are set in child into itself using reflection.
|
|
func (spec *TargetSpec) overrideProperties(child *TargetSpec) error {
|
|
specType := reflect.TypeOf(spec).Elem()
|
|
specValue := reflect.ValueOf(spec).Elem()
|
|
childValue := reflect.ValueOf(child).Elem()
|
|
|
|
for i := 0; i < specType.NumField(); i++ {
|
|
field := specType.Field(i)
|
|
src := childValue.Field(i)
|
|
dst := specValue.Field(i)
|
|
|
|
switch kind := field.Type.Kind(); kind {
|
|
case reflect.String: // for strings, just copy the field of child to spec if not empty
|
|
if src.Len() > 0 {
|
|
dst.Set(src)
|
|
}
|
|
case reflect.Uint, reflect.Uint32, reflect.Uint64: // for Uint, copy if not zero
|
|
if src.Uint() != 0 {
|
|
dst.Set(src)
|
|
}
|
|
case reflect.Bool:
|
|
if src.Bool() {
|
|
dst.Set(src)
|
|
}
|
|
case reflect.Ptr: // for pointers, copy if not nil
|
|
if !src.IsNil() {
|
|
dst.Set(src)
|
|
}
|
|
case reflect.Slice: // for slices, append the field and check for duplicates
|
|
dst.Set(reflect.AppendSlice(dst, src))
|
|
for i := 0; i < dst.Len(); i++ {
|
|
v := dst.Index(i).String()
|
|
for j := i + 1; j < dst.Len(); j++ {
|
|
w := dst.Index(j).String()
|
|
if v == w {
|
|
return fmt.Errorf("duplicate value '%s' in field %s", v, field.Name)
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
return fmt.Errorf("unknown field type: %s", kind)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// load reads a target specification from the JSON in the given io.Reader. It
|
|
// may load more targets specified using the "inherits" property.
|
|
func (spec *TargetSpec) load(r io.Reader) error {
|
|
err := json.NewDecoder(r).Decode(spec)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// loadFromGivenStr loads the TargetSpec from the given string that could be:
|
|
// - targets/ directory inside the compiler sources
|
|
// - a relative or absolute path to custom (project specific) target specification .json file;
|
|
// the Inherits[] could contain the files from target folder (ex. stm32f4disco)
|
|
// as well as path to custom files (ex. myAwesomeProject.json)
|
|
func (spec *TargetSpec) loadFromGivenStr(str string) error {
|
|
path := ""
|
|
if strings.HasSuffix(str, ".json") {
|
|
path, _ = filepath.Abs(str)
|
|
} else {
|
|
path = filepath.Join(goenv.Get("TINYGOROOT"), "targets", strings.ToLower(str)+".json")
|
|
}
|
|
fp, err := os.Open(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer fp.Close()
|
|
return spec.load(fp)
|
|
}
|
|
|
|
// resolveInherits loads inherited targets, recursively.
|
|
func (spec *TargetSpec) resolveInherits() error {
|
|
// First create a new spec with all the inherited properties.
|
|
newSpec := &TargetSpec{}
|
|
for _, name := range spec.Inherits {
|
|
subtarget := &TargetSpec{}
|
|
err := subtarget.loadFromGivenStr(name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = subtarget.resolveInherits()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = newSpec.overrideProperties(subtarget)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// When all properties are loaded, make sure they are properly inherited.
|
|
err := newSpec.overrideProperties(spec)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*spec = *newSpec
|
|
|
|
return nil
|
|
}
|
|
|
|
// Load a target specification.
|
|
func LoadTarget(options *Options) (*TargetSpec, error) {
|
|
if options.Target == "" {
|
|
return defaultTarget(options)
|
|
}
|
|
|
|
// See whether there is a target specification for this target (e.g.
|
|
// Arduino).
|
|
spec := &TargetSpec{}
|
|
err := spec.loadFromGivenStr(options.Target)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// Successfully loaded this target from a built-in .json file. Make sure
|
|
// it includes all parents as specified in the "inherits" key.
|
|
err = spec.resolveInherits()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%s : %w", options.Target, err)
|
|
}
|
|
|
|
if spec.Scheduler == "asyncify" {
|
|
spec.ExtraFiles = append(spec.ExtraFiles, "src/internal/task/task_asyncify_wasm.S")
|
|
}
|
|
|
|
return spec, nil
|
|
}
|
|
|
|
// GetTargetSpecs retrieves target specifications from the TINYGOROOT targets
|
|
// directory. Only valid target JSON files are considered, and the function
|
|
// returns a map of target names to their respective TargetSpec.
|
|
func GetTargetSpecs() (map[string]*TargetSpec, error) {
|
|
dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets")
|
|
entries, err := os.ReadDir(dir)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not list targets: %w", err)
|
|
}
|
|
|
|
maps := map[string]*TargetSpec{}
|
|
for _, entry := range entries {
|
|
entryInfo, err := entry.Info()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not get entry info: %w", err)
|
|
}
|
|
if !entryInfo.Mode().IsRegular() || !strings.HasSuffix(entry.Name(), ".json") {
|
|
// Only inspect JSON files.
|
|
continue
|
|
}
|
|
path := filepath.Join(dir, entry.Name())
|
|
spec, err := LoadTarget(&Options{Target: path})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not list target: %w", err)
|
|
}
|
|
if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == "" {
|
|
// This doesn't look like a regular target file, but rather like
|
|
// a parent target (such as targets/cortex-m.json).
|
|
continue
|
|
}
|
|
name := entry.Name()
|
|
name = name[:len(name)-5]
|
|
maps[name] = spec
|
|
}
|
|
return maps, nil
|
|
}
|
|
|
|
// Load a target from environment variables (which default to
|
|
// runtime.GOOS/runtime.GOARCH).
|
|
func defaultTarget(options *Options) (*TargetSpec, error) {
|
|
spec := TargetSpec{
|
|
GOOS: options.GOOS,
|
|
GOARCH: options.GOARCH,
|
|
BuildTags: []string{options.GOOS, options.GOARCH},
|
|
GC: "precise",
|
|
Scheduler: "tasks",
|
|
Linker: "cc",
|
|
DefaultStackSize: 1024 * 64, // 64kB
|
|
GDB: []string{"gdb"},
|
|
PortReset: "false",
|
|
}
|
|
|
|
// Configure target based on GOARCH.
|
|
var llvmarch string
|
|
switch options.GOARCH {
|
|
case "386":
|
|
llvmarch = "i386"
|
|
spec.CPU = "pentium4"
|
|
spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
|
case "amd64":
|
|
llvmarch = "x86_64"
|
|
spec.CPU = "x86-64"
|
|
spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
|
case "arm":
|
|
spec.CPU = "generic"
|
|
spec.CFlags = append(spec.CFlags, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
|
|
subarch := strings.Split(options.GOARM, ",")
|
|
if len(subarch) > 2 {
|
|
return nil, fmt.Errorf("invalid GOARM=%s, must be of form <num>,[hardfloat|softfloat]", options.GOARM)
|
|
}
|
|
archLevel := subarch[0]
|
|
var fpu string
|
|
if len(subarch) >= 2 {
|
|
fpu = subarch[1]
|
|
} else {
|
|
// Pick the default fpu value: softfloat for armv5 and hardfloat
|
|
// above that.
|
|
if archLevel == "5" {
|
|
fpu = "softfloat"
|
|
} else {
|
|
fpu = "hardfloat"
|
|
}
|
|
}
|
|
switch fpu {
|
|
case "softfloat":
|
|
spec.CFlags = append(spec.CFlags, "-msoft-float")
|
|
spec.SoftFloat = true
|
|
case "hardfloat":
|
|
// Hardware floating point support is the default everywhere except
|
|
// on ARMv5 where it needs to be enabled explicitly.
|
|
if archLevel == "5" {
|
|
spec.CFlags = append(spec.CFlags, "-mfpu=vfpv2")
|
|
}
|
|
default:
|
|
return nil, fmt.Errorf("invalid extension GOARM=%s, must be softfloat or hardfloat", options.GOARM)
|
|
}
|
|
switch archLevel {
|
|
case "5":
|
|
llvmarch = "armv5"
|
|
if spec.SoftFloat {
|
|
spec.Features = "+armv5t,+soft-float,+strict-align,-aes,-bf16,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-mve,-mve.fp,-neon,-sha2,-thumb-mode,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
|
} else {
|
|
spec.Features = "+armv5t,+fp64,+strict-align,+vfp2,+vfp2sp,-aes,-d32,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-neon,-sha2,-thumb-mode,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
|
}
|
|
case "6":
|
|
llvmarch = "armv6"
|
|
if spec.SoftFloat {
|
|
spec.Features = "+armv6,+dsp,+soft-float,+strict-align,-aes,-bf16,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-mve,-mve.fp,-neon,-sha2,-thumb-mode,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
|
} else {
|
|
spec.Features = "+armv6,+dsp,+fp64,+strict-align,+vfp2,+vfp2sp,-aes,-d32,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-neon,-sha2,-thumb-mode,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
|
}
|
|
case "7":
|
|
llvmarch = "armv7"
|
|
if spec.SoftFloat {
|
|
spec.Features = "+armv7-a,+dsp,+soft-float,-aes,-bf16,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-mve,-mve.fp,-neon,-sha2,-thumb-mode,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
|
} else {
|
|
spec.Features = "+armv7-a,+d32,+dsp,+fp64,+neon,+vfp2,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,-aes,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-sha2,-thumb-mode,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
|
}
|
|
default:
|
|
return nil, fmt.Errorf("invalid GOARM=%s, must be of form <num>,[hardfloat|softfloat] where num is 5, 6, or 7", options.GOARM)
|
|
}
|
|
case "arm64":
|
|
spec.CPU = "generic"
|
|
llvmarch = "aarch64"
|
|
if options.GOOS == "darwin" {
|
|
spec.Features = "+fp-armv8,+neon"
|
|
// Looks like Apple prefers to call this architecture ARM64
|
|
// instead of AArch64.
|
|
llvmarch = "arm64"
|
|
} else if options.GOOS == "windows" {
|
|
spec.Features = "+fp-armv8,+neon,-fmv"
|
|
} else { // linux
|
|
spec.Features = "+fp-armv8,+neon,-fmv,-outline-atomics"
|
|
}
|
|
case "mips", "mipsle":
|
|
spec.CPU = "mips32r2"
|
|
spec.CFlags = append(spec.CFlags, "-fno-pic")
|
|
if options.GOOS == "mips" {
|
|
llvmarch = "mips" // big endian
|
|
} else {
|
|
llvmarch = "mipsel" // little endian
|
|
}
|
|
switch options.GOMIPS {
|
|
case "hardfloat":
|
|
spec.Features = "+fpxx,+mips32r2,+nooddspreg,-noabicalls"
|
|
case "softfloat":
|
|
spec.SoftFloat = true
|
|
spec.Features = "+mips32r2,+soft-float,-noabicalls"
|
|
spec.CFlags = append(spec.CFlags, "-msoft-float")
|
|
default:
|
|
return nil, fmt.Errorf("invalid GOMIPS=%s: must be hardfloat or softfloat", options.GOMIPS)
|
|
}
|
|
case "wasm":
|
|
llvmarch = "wasm32"
|
|
spec.CPU = "generic"
|
|
spec.Features = "+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext"
|
|
spec.BuildTags = append(spec.BuildTags, "tinygo.wasm")
|
|
spec.CFlags = append(spec.CFlags,
|
|
"-mbulk-memory",
|
|
"-mnontrapping-fptoint",
|
|
"-msign-ext",
|
|
)
|
|
default:
|
|
return nil, fmt.Errorf("unknown GOARCH=%s", options.GOARCH)
|
|
}
|
|
|
|
// Configure target based on GOOS.
|
|
llvmos := options.GOOS
|
|
llvmvendor := "unknown"
|
|
switch options.GOOS {
|
|
case "darwin":
|
|
platformVersion := "10.12.0"
|
|
if options.GOARCH == "arm64" {
|
|
platformVersion = "11.0.0" // first macosx platform with arm64 support
|
|
}
|
|
llvmvendor = "apple"
|
|
spec.Linker = "ld.lld"
|
|
spec.Libc = "darwin-libSystem"
|
|
// Use macosx* instead of darwin, otherwise darwin/arm64 will refer to
|
|
// iOS!
|
|
llvmos = "macosx" + platformVersion
|
|
spec.LDFlags = append(spec.LDFlags,
|
|
"-flavor", "darwin",
|
|
"-dead_strip",
|
|
"-arch", llvmarch,
|
|
"-platform_version", "macos", platformVersion, platformVersion,
|
|
)
|
|
spec.ExtraFiles = append(spec.ExtraFiles,
|
|
"src/runtime/runtime_unix.c")
|
|
case "linux":
|
|
spec.Linker = "ld.lld"
|
|
spec.RTLib = "compiler-rt"
|
|
spec.Libc = "musl"
|
|
spec.LDFlags = append(spec.LDFlags, "--gc-sections")
|
|
if options.GOARCH == "arm64" {
|
|
// Disable outline atomics. For details, see:
|
|
// https://cpufun.substack.com/p/atomics-in-aarch64
|
|
// A better way would be to fully support outline atomics, which
|
|
// makes atomics slightly more efficient on systems with many cores.
|
|
// But the instructions are only supported on newer aarch64 CPUs, so
|
|
// this feature is normally put in a system library which does
|
|
// feature detection for you.
|
|
// We take the lazy way out and simply disable this feature, instead
|
|
// of enabling it in compiler-rt (which is a bit more complicated).
|
|
// We don't really need this feature anyway as we don't even support
|
|
// proper threading.
|
|
spec.CFlags = append(spec.CFlags, "-mno-outline-atomics")
|
|
}
|
|
spec.ExtraFiles = append(spec.ExtraFiles,
|
|
"src/runtime/runtime_unix.c")
|
|
case "windows":
|
|
spec.Linker = "ld.lld"
|
|
spec.Libc = "mingw-w64"
|
|
// Note: using a medium code model, low image base and no ASLR
|
|
// because Go doesn't really need those features. ASLR patches
|
|
// around issues for unsafe languages like C/C++ that are not
|
|
// normally present in Go (without explicitly opting in).
|
|
// For more discussion:
|
|
// https://groups.google.com/g/Golang-nuts/c/Jd9tlNc6jUE/m/Zo-7zIP_m3MJ?pli=1
|
|
switch options.GOARCH {
|
|
case "amd64":
|
|
spec.LDFlags = append(spec.LDFlags,
|
|
"-m", "i386pep",
|
|
"--image-base", "0x400000",
|
|
)
|
|
case "arm64":
|
|
spec.LDFlags = append(spec.LDFlags,
|
|
"-m", "arm64pe",
|
|
)
|
|
}
|
|
spec.LDFlags = append(spec.LDFlags,
|
|
"-Bdynamic",
|
|
"--gc-sections",
|
|
"--no-insert-timestamp",
|
|
"--no-dynamicbase",
|
|
)
|
|
case "wasip1":
|
|
spec.GC = "" // use default GC
|
|
spec.Scheduler = "asyncify"
|
|
spec.Linker = "wasm-ld"
|
|
spec.RTLib = "compiler-rt"
|
|
spec.Libc = "wasi-libc"
|
|
spec.DefaultStackSize = 1024 * 64 // 64kB
|
|
spec.LDFlags = append(spec.LDFlags,
|
|
"--stack-first",
|
|
"--no-demangle",
|
|
)
|
|
spec.Emulator = "wasmtime --dir={tmpDir}::/tmp {}"
|
|
spec.ExtraFiles = append(spec.ExtraFiles,
|
|
"src/runtime/asm_tinygowasm.S",
|
|
"src/internal/task/task_asyncify_wasm.S",
|
|
)
|
|
llvmos = "wasi"
|
|
default:
|
|
return nil, fmt.Errorf("unknown GOOS=%s", options.GOOS)
|
|
}
|
|
|
|
// Target triples (which actually have four components, but are called
|
|
// triples for historical reasons) have the form:
|
|
// arch-vendor-os-environment
|
|
spec.Triple = llvmarch + "-" + llvmvendor + "-" + llvmos
|
|
if options.GOOS == "windows" {
|
|
spec.Triple += "-gnu"
|
|
} else if options.GOOS == "linux" {
|
|
// We use musl on Linux (not glibc) so we should use -musleabi* instead
|
|
// of -gnueabi*.
|
|
// The *hf suffix selects between soft/hard floating point ABI.
|
|
if spec.SoftFloat {
|
|
spec.Triple += "-musleabi"
|
|
} else {
|
|
spec.Triple += "-musleabihf"
|
|
}
|
|
}
|
|
|
|
// Add extra assembly files (needed for the scheduler etc).
|
|
if options.GOARCH != "wasm" {
|
|
suffix := ""
|
|
if options.GOOS == "windows" && options.GOARCH == "amd64" {
|
|
// Windows uses a different calling convention on amd64 from other
|
|
// operating systems so we need separate assembly files.
|
|
suffix = "_windows"
|
|
}
|
|
asmGoarch := options.GOARCH
|
|
if options.GOARCH == "mips" || options.GOARCH == "mipsle" {
|
|
asmGoarch = "mipsx"
|
|
}
|
|
spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/asm_"+asmGoarch+suffix+".S")
|
|
spec.ExtraFiles = append(spec.ExtraFiles, "src/internal/task/task_stack_"+asmGoarch+suffix+".S")
|
|
}
|
|
|
|
// Configure the emulator.
|
|
if options.GOARCH != runtime.GOARCH {
|
|
// Some educated guesses as to how to invoke helper programs.
|
|
spec.GDB = []string{"gdb-multiarch"}
|
|
if options.GOOS == "linux" {
|
|
switch options.GOARCH {
|
|
case "386":
|
|
// amd64 can _usually_ run 32-bit programs, so skip the emulator in that case.
|
|
if runtime.GOARCH != "amd64" {
|
|
spec.Emulator = "qemu-i386 {}"
|
|
}
|
|
case "amd64":
|
|
spec.Emulator = "qemu-x86_64 {}"
|
|
case "arm":
|
|
spec.Emulator = "qemu-arm {}"
|
|
case "arm64":
|
|
spec.Emulator = "qemu-aarch64 {}"
|
|
case "mips":
|
|
spec.Emulator = "qemu-mips {}"
|
|
case "mipsle":
|
|
spec.Emulator = "qemu-mipsel {}"
|
|
}
|
|
}
|
|
}
|
|
if options.GOOS != runtime.GOOS {
|
|
if options.GOOS == "windows" {
|
|
spec.Emulator = "wine {}"
|
|
}
|
|
}
|
|
|
|
return &spec, nil
|
|
}
|
|
|
|
// LookupGDB looks up a gdb executable.
|
|
func (spec *TargetSpec) LookupGDB() (string, error) {
|
|
if len(spec.GDB) == 0 {
|
|
return "", errors.New("gdb not configured in the target specification")
|
|
}
|
|
for _, d := range spec.GDB {
|
|
_, err := exec.LookPath(d)
|
|
if err == nil {
|
|
return d, nil
|
|
}
|
|
}
|
|
return "", errors.New("no gdb found configured in the target specification (" + strings.Join(spec.GDB, ", ") + ")")
|
|
}
|
|
|