diff --git a/target.go b/target.go index b67eddff..8d425595 100644 --- a/target.go +++ b/target.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "io" "os" "os/user" "path/filepath" @@ -17,6 +18,7 @@ import ( // 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"` Triple string `json:"llvm-target"` BuildTags []string `json:"build-tags"` Linker string `json:"linker"` @@ -30,40 +32,127 @@ type TargetSpec struct { GDBCmds []string `json:"gdb-initial-cmds"` } -// Load a target specification +// copyProperties copies all properties that are set in spec2 into itself. +func (spec *TargetSpec) copyProperties(spec2 *TargetSpec) { + // TODO: simplify this using reflection? Inherits and BuildTags are special + // cases, but the rest can simply be copied if set. + spec.Inherits = append(spec.Inherits, spec2.Inherits...) + if spec2.Triple != "" { + spec.Triple = spec2.Triple + } + spec.BuildTags = append(spec.BuildTags, spec2.BuildTags...) + if spec2.Linker != "" { + spec.Linker = spec2.Linker + } + if spec2.RTLib != "" { + spec.RTLib = spec2.RTLib + } + if len(spec2.PreLinkArgs) != 0 { + spec.PreLinkArgs = spec2.PreLinkArgs + } + if spec2.Objcopy != "" { + spec.Objcopy = spec2.Objcopy + } + if len(spec2.Emulator) != 0 { + spec.Emulator = spec2.Emulator + } + if spec2.Flasher != "" { + spec.Flasher = spec2.Flasher + } + if len(spec2.OCDDaemon) != 0 { + spec.OCDDaemon = spec2.OCDDaemon + } + if spec2.GDB != "" { + spec.GDB = spec2.GDB + } + if len(spec2.GDBCmds) != 0 { + spec.GDBCmds = spec2.GDBCmds + } +} + +// 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 +} + +// loadFromName loads the given target from the targets/ directory inside the +// compiler sources. +func (spec *TargetSpec) loadFromName(name string) error { + path := filepath.Join(sourceDir(), "targets", strings.ToLower(name)+".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.loadFromName(name) + if err != nil { + return err + } + err = subtarget.resolveInherits() + if err != nil { + return err + } + newSpec.copyProperties(subtarget) + } + + // When all properties are loaded, make sure they are properly inherited. + newSpec.copyProperties(spec) + *spec = *newSpec + + return nil +} + +// Load a target specification. func LoadTarget(target string) (*TargetSpec, error) { if target == "" { target = llvm.DefaultTargetTriple() } - spec := &TargetSpec{ - Triple: target, - BuildTags: []string{runtime.GOOS, runtime.GOARCH}, - Linker: "cc", - PreLinkArgs: []string{"-no-pie"}, // WARNING: clang < 5.0 requires -nopie - Objcopy: "objcopy", - GDB: "gdb", - GDBCmds: []string{"run"}, - } - // See whether there is a target specification for this target (e.g. // Arduino). - path := filepath.Join(sourceDir(), "targets", strings.ToLower(target)+".json") - if fp, err := os.Open(path); err == nil { - defer fp.Close() - *spec = TargetSpec{} // reset all fields - err := json.NewDecoder(fp).Decode(spec) + spec := &TargetSpec{} + err := spec.loadFromName(target) + if err == nil { + // 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, err } + return spec, nil } else if !os.IsNotExist(err) { - // Expected a 'file not found' error, got something else. + // Expected a 'file not found' error, got something else. Report it as + // an error. return nil, err } else { - // No target spec available. Use the default one. + // No target spec available. Use the default one, useful on most systems + // with a regular OS. + *spec = TargetSpec{ + Triple: target, + BuildTags: []string{runtime.GOOS, runtime.GOARCH}, + Linker: "cc", + PreLinkArgs: []string{"-no-pie"}, // WARNING: clang < 5.0 requires -nopie + Objcopy: "objcopy", + GDB: "gdb", + GDBCmds: []string{"run"}, + } + return spec, nil } - - return spec, nil } // Return the source directory of this package, or "." when it cannot be diff --git a/targets/bluepill.json b/targets/bluepill.json index cded74db..3c086ec6 100644 --- a/targets/bluepill.json +++ b/targets/bluepill.json @@ -1,9 +1,18 @@ { + "inherits": ["cortex-m"], "llvm-target": "armv7m-none-eabi", - "build-tags": ["bluepill", "stm32f103xx", "stm32", "tinygo.arm", "js", "wasm"], - "linker": "arm-none-eabi-gcc", - "rtlib": "compiler-rt", - "pre-link-args": ["-nostdlib", "-nostartfiles", "-mcpu=cortex-m3", "-mthumb", "-T", "targets/stm32.ld", "-Wl,--gc-sections", "-fno-exceptions", "-fno-unwind-tables", "-ffunction-sections", "-fdata-sections", "-Os", "src/device/stm32/stm32f103xx.s"], - "objcopy": "arm-none-eabi-objcopy", + "build-tags": ["bluepill", "stm32f103xx", "stm32"], + "pre-link-args": [ + "-nostdlib", + "-nostartfiles", + "-mcpu=cortex-m3", + "-mthumb", + "-T", "targets/stm32.ld", + "-Wl,--gc-sections", + "-fno-exceptions", "-fno-unwind-tables", + "-ffunction-sections", "-fdata-sections", + "-Os", + "src/device/stm32/stm32f103xx.s" + ], "flash": "openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c 'program {hex} reset exit'" } diff --git a/targets/cortex-m.json b/targets/cortex-m.json new file mode 100644 index 00000000..71d354f4 --- /dev/null +++ b/targets/cortex-m.json @@ -0,0 +1,7 @@ +{ + "build-tags": ["tinygo.arm", "js", "wasm"], + "linker": "arm-none-eabi-gcc", + "rtlib": "compiler-rt", + "objcopy": "arm-none-eabi-objcopy", + "gdb": "arm-none-eabi-gdb" +} diff --git a/targets/microbit.json b/targets/microbit.json index e9e5ec9b..d2cd698d 100644 --- a/targets/microbit.json +++ b/targets/microbit.json @@ -1,26 +1,7 @@ { - "llvm-target": "armv6m-none-eabi", - "build-tags": ["microbit", "nrf51822", "nrf51", "nrf", "tinygo.arm", "js", "wasm"], - "linker": "arm-none-eabi-gcc", - "rtlib": "compiler-rt", - "pre-link-args": [ - "-nostdlib", - "-nostartfiles", - "-mcpu=cortex-m0", - "-mthumb", - "-T", "targets/nrf51.ld", - "-Wl,--gc-sections", - "-fno-exceptions", "-fno-unwind-tables", - "-ffunction-sections", "-fdata-sections", - "-Os", - "-DNRF51", - "-Ilib/CMSIS/CMSIS/Include", - "lib/nrfx/mdk/system_nrf51.c", - "src/device/nrf/nrf51.s" - ], - "objcopy": "arm-none-eabi-objcopy", + "inherits": ["nrf51"], + "build-tags": ["microbit"], "flash": "openocd -f interface/cmsis-dap.cfg -f target/nrf51.cfg -c 'program {hex} reset exit'", "ocd-daemon": ["openocd", "-f", "interface/cmsis-dap.cfg", "-f", "target/nrf51.cfg"], - "gdb": "arm-none-eabi-gdb", "gdb-initial-cmds": ["target remote :3333", "monitor halt", "load", "monitor reset", "c"] } diff --git a/targets/nrf51.json b/targets/nrf51.json new file mode 100644 index 00000000..68c6b14f --- /dev/null +++ b/targets/nrf51.json @@ -0,0 +1,20 @@ +{ + "inherits": ["cortex-m"], + "llvm-target": "armv6m-none-eabi", + "build-tags": ["nrf51822", "nrf51", "nrf"], + "pre-link-args": [ + "-nostdlib", + "-nostartfiles", + "-mcpu=cortex-m0", + "-mthumb", + "-T", "targets/nrf51.ld", + "-Wl,--gc-sections", + "-fno-exceptions", "-fno-unwind-tables", + "-ffunction-sections", "-fdata-sections", + "-Os", + "-DNRF51", + "-Ilib/CMSIS/CMSIS/Include", + "lib/nrfx/mdk/system_nrf51.c", + "src/device/nrf/nrf51.s" + ] +} diff --git a/targets/nrf52.json b/targets/nrf52.json new file mode 100644 index 00000000..53ff2a47 --- /dev/null +++ b/targets/nrf52.json @@ -0,0 +1,20 @@ +{ + "inherits": ["cortex-m"], + "llvm-target": "armv7em-none-eabi", + "build-tags": ["nrf52", "nrf"], + "pre-link-args": [ + "-nostdlib", + "-nostartfiles", + "-mcpu=cortex-m4", + "-mthumb", + "-T", "targets/nrf52.ld", + "-Wl,--gc-sections", + "-fno-exceptions", "-fno-unwind-tables", + "-ffunction-sections", "-fdata-sections", + "-Os", + "-DNRF52832_XXAA", + "-Ilib/CMSIS/CMSIS/Include", + "lib/nrfx/mdk/system_nrf52.c", + "src/device/nrf/nrf52.s" + ] +} diff --git a/targets/nrf52840-mdk.json b/targets/nrf52840-mdk.json index 7be43642..388c325b 100644 --- a/targets/nrf52840-mdk.json +++ b/targets/nrf52840-mdk.json @@ -1,25 +1,7 @@ { - "llvm-target": "armv7em-none-eabi", - "build-tags": ["nrf52840_mdk", "nrf52840", "nrf", "tinygo.arm", "js", "wasm"], - "linker": "arm-none-eabi-gcc", - "pre-link-args": [ - "-nostdlib", - "-nostartfiles", - "-mcpu=cortex-m4", - "-mthumb", - "-T", "targets/nrf52840.ld", - "-Wl,--gc-sections", - "-fno-exceptions", "-fno-unwind-tables", - "-ffunction-sections", "-fdata-sections", - "-Os", - "-DNRF52840_XXAA", - "-Ilib/CMSIS/CMSIS/Include", - "lib/nrfx/mdk/system_nrf52840.c", - "src/device/nrf/nrf52840.s" - ], - "objcopy": "arm-none-eabi-objcopy", + "inherits": ["nrf52840"], + "build-tags": ["nrf52840_mdk"], "flash": "openocd -f interface/cmsis-dap.cfg -f target/nrf51.cfg -c 'program {hex} reset exit'", "ocd-daemon": ["openocd", "-f", "interface/cmsis-dap.cfg", "-f", "target/nrf51.cfg"], - "gdb": "arm-none-eabi-gdb", "gdb-initial-cmds": ["target remote :3333", "monitor halt", "load", "monitor reset", "c"] } diff --git a/targets/nrf52840.json b/targets/nrf52840.json new file mode 100644 index 00000000..8346735c --- /dev/null +++ b/targets/nrf52840.json @@ -0,0 +1,20 @@ +{ + "inherits": ["cortex-m"], + "llvm-target": "armv7em-none-eabi", + "build-tags": ["nrf52840", "nrf"], + "pre-link-args": [ + "-nostdlib", + "-nostartfiles", + "-mcpu=cortex-m4", + "-mthumb", + "-T", "targets/nrf52840.ld", + "-Wl,--gc-sections", + "-fno-exceptions", "-fno-unwind-tables", + "-ffunction-sections", "-fdata-sections", + "-Os", + "-DNRF52840_XXAA", + "-Ilib/CMSIS/CMSIS/Include", + "lib/nrfx/mdk/system_nrf52840.c", + "src/device/nrf/nrf52840.s" + ] +} diff --git a/targets/pca10040.json b/targets/pca10040.json index 0a3cbb4e..1bff6e8c 100644 --- a/targets/pca10040.json +++ b/targets/pca10040.json @@ -1,26 +1,7 @@ { - "llvm-target": "armv7em-none-eabi", - "build-tags": ["pca10040", "nrf52832", "nrf52", "nrf", "tinygo.arm", "js", "wasm"], - "linker": "arm-none-eabi-gcc", - "rtlib": "compiler-rt", - "pre-link-args": [ - "-nostdlib", - "-nostartfiles", - "-mcpu=cortex-m4", - "-mthumb", - "-T", "targets/nrf52.ld", - "-Wl,--gc-sections", - "-fno-exceptions", "-fno-unwind-tables", - "-ffunction-sections", "-fdata-sections", - "-Os", - "-DNRF52832_XXAA", - "-Ilib/CMSIS/CMSIS/Include", - "lib/nrfx/mdk/system_nrf52.c", - "src/device/nrf/nrf52.s" - ], - "objcopy": "arm-none-eabi-objcopy", + "inherits": ["nrf52"], + "build-tags": ["pca10040"], "flash": "nrfjprog -f nrf52 --sectorerase --program {hex} --reset", "ocd-daemon": ["openocd", "-f", "interface/jlink.cfg", "-c", "transport select swd", "-f", "target/nrf51.cfg"], - "gdb": "arm-none-eabi-gdb", "gdb-initial-cmds": ["target remote :3333", "monitor halt", "load", "monitor reset", "c"] } diff --git a/targets/qemu.json b/targets/qemu.json index cd0ecaf5..7cc23da8 100644 --- a/targets/qemu.json +++ b/targets/qemu.json @@ -1,8 +1,7 @@ { + "inherits": ["cortex-m"], "llvm-target": "armv7m-none-eabi", - "build-tags": ["qemu", "lm3s6965", "tinygo.arm", "js", "wasm"], - "linker": "arm-none-eabi-gcc", - "rtlib": "compiler-rt", + "build-tags": ["qemu", "lm3s6965"], "pre-link-args": [ "-nostdlib", "-nostartfiles", @@ -15,6 +14,5 @@ "-Os", "targets/cortex-m.s" ], - "objcopy": "arm-none-eabi-objcopy", "emulator": ["qemu-system-arm", "-machine", "lm3s6965evb", "-semihosting", "-nographic", "-kernel"] }