aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2022-04-22 17:45:19 +0200
committerRon Evans <[email protected]>2022-04-28 07:50:03 +0200
commitbd56636d5802cdeb323851ec2431bb3f78f94eed (patch)
tree86ba8d730bc0c7883bf78d137c4cf6240acfabef
parent4fe3a379a507282cea2e131879cd832cfe5a2928 (diff)
downloadtinygo-bd56636d5802cdeb323851ec2431bb3f78f94eed.tar.gz
tinygo-bd56636d5802cdeb323851ec2431bb3f78f94eed.zip
all: make emulator command a string instead of a []string
This matches the flash-command and is generally a bit easier to work with. This commit also prepares for allowing multiple formats to be used in the emulator command, which is necessary for the esp32.
-rw-r--r--compileopts/config.go36
-rw-r--r--compileopts/target.go29
-rw-r--r--compileopts/target_test.go5
-rw-r--r--main.go53
-rw-r--r--main_test.go11
-rw-r--r--targets/arduino-nano.json2
-rw-r--r--targets/arduino.json2
-rw-r--r--targets/atmega1284p.json2
-rw-r--r--targets/cortex-m-qemu.json2
-rw-r--r--targets/digispark.json2
-rw-r--r--targets/gameboy-advance.json2
-rw-r--r--targets/hifive1-qemu.json2
-rw-r--r--targets/riscv-qemu.json2
-rw-r--r--targets/wasi.json2
-rw-r--r--targets/wasm.json2
15 files changed, 81 insertions, 73 deletions
diff --git a/compileopts/config.go b/compileopts/config.go
index 9fb6a3bbc..d7dbb41c3 100644
--- a/compileopts/config.go
+++ b/compileopts/config.go
@@ -10,6 +10,7 @@ import (
"regexp"
"strings"
+ "github.com/google/shlex"
"github.com/tinygo-org/tinygo/goenv"
)
@@ -494,13 +495,38 @@ func (c *Config) WasmAbi() string {
return c.Target.WasmAbi
}
-// Emulator returns the emulator target config
-func (c *Config) Emulator() []string {
+// EmulatorName is a shorthand to get the command for this emulator, something
+// like qemu-system-arm or simavr.
+func (c *Config) EmulatorName() string {
+ parts := strings.SplitN(c.Target.Emulator, " ", 2)
+ if len(parts) > 1 {
+ return parts[0]
+ }
+ return ""
+}
+
+// EmulatorFormat returns the binary format for the emulator and the associated
+// file extension. An empty string means to pass directly whatever the linker
+// produces directly without conversion.
+func (c *Config) EmulatorFormat() (format, fileExt string) {
+ return "", ""
+}
+
+// Emulator returns a ready-to-run command to run the given binary in an
+// emulator. Give it the format (returned by EmulatorFormat()) and the path to
+// the compiled binary.
+func (c *Config) Emulator(format, binary string) ([]string, error) {
+ parts, err := shlex.Split(c.Target.Emulator)
+ if err != nil {
+ return nil, fmt.Errorf("could not parse emulator command: %w", err)
+ }
var emulator []string
- for _, s := range c.Target.Emulator {
- emulator = append(emulator, strings.ReplaceAll(s, "{root}", goenv.Get("TINYGOROOT")))
+ for _, s := range parts {
+ s = strings.ReplaceAll(s, "{root}", goenv.Get("TINYGOROOT"))
+ s = strings.ReplaceAll(s, "{"+format+"}", binary)
+ emulator = append(emulator, s)
}
- return emulator
+ return emulator, nil
}
type TestConfig struct {
diff --git a/compileopts/target.go b/compileopts/target.go
index 26f007538..6a1dbf126 100644
--- a/compileopts/target.go
+++ b/compileopts/target.go
@@ -44,8 +44,8 @@ type TargetSpec struct {
LDFlags []string `json:"ldflags"`
LinkerScript string `json:"linkerscript"`
ExtraFiles []string `json:"extra-files"`
- RP2040BootPatch *bool `json:"rp2040-boot-patch"` // Patch RP2040 2nd stage bootloader checksum
- Emulator []string `json:"emulator" override:"copy"` // inherited Emulator must not be append
+ RP2040BootPatch *bool `json:"rp2040-boot-patch"` // Patch RP2040 2nd stage bootloader checksum
+ Emulator string `json:"emulator"`
FlashCommand string `json:"flash-command"`
GDB []string `json:"gdb"`
PortReset string `json:"flash-1200-bps-reset"`
@@ -90,19 +90,8 @@ func (spec *TargetSpec) overrideProperties(child *TargetSpec) {
if !src.IsNil() {
dst.Set(src)
}
- case reflect.Slice: // for slices...
- if src.Len() > 0 { // ... if not empty ...
- switch tag := field.Tag.Get("override"); tag {
- case "copy":
- // copy the field of child to spec
- dst.Set(src)
- case "append", "":
- // or append the field of child to spec
- dst.Set(reflect.AppendSlice(dst, src))
- default:
- panic("override mode must be 'copy' or 'append' (default). I don't know how to '" + tag + "'.")
- }
- }
+ case reflect.Slice: // for slices, append the field
+ dst.Set(reflect.AppendSlice(dst, src))
default:
panic("unknown field type : " + kind.String())
}
@@ -335,20 +324,20 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
case "386":
// amd64 can _usually_ run 32-bit programs, so skip the emulator in that case.
if runtime.GOARCH != "amd64" {
- spec.Emulator = []string{"qemu-i386"}
+ spec.Emulator = "qemu-i386 {}"
}
case "amd64":
- spec.Emulator = []string{"qemu-x86_64"}
+ spec.Emulator = "qemu-x86_64 {}"
case "arm":
- spec.Emulator = []string{"qemu-arm"}
+ spec.Emulator = "qemu-arm {}"
case "arm64":
- spec.Emulator = []string{"qemu-aarch64"}
+ spec.Emulator = "qemu-aarch64 {}"
}
}
}
if goos != runtime.GOOS {
if goos == "windows" {
- spec.Emulator = []string{"wine"}
+ spec.Emulator = "wine {}"
}
}
return &spec, nil
diff --git a/compileopts/target_test.go b/compileopts/target_test.go
index 6aea7e817..8f7b99b2e 100644
--- a/compileopts/target_test.go
+++ b/compileopts/target_test.go
@@ -29,7 +29,6 @@ func TestOverrideProperties(t *testing.T) {
CPU: "baseCpu",
CFlags: []string{"-base-foo", "-base-bar"},
BuildTags: []string{"bt1", "bt2"},
- Emulator: []string{"be1", "be2"},
DefaultStackSize: 42,
AutoStackSize: &baseAutoStackSize,
}
@@ -38,7 +37,6 @@ func TestOverrideProperties(t *testing.T) {
GOOS: "",
CPU: "chlidCpu",
CFlags: []string{"-child-foo", "-child-bar"},
- Emulator: []string{"ce1", "ce2"},
AutoStackSize: &childAutoStackSize,
DefaultStackSize: 64,
}
@@ -57,9 +55,6 @@ func TestOverrideProperties(t *testing.T) {
if !reflect.DeepEqual(base.BuildTags, []string{"bt1", "bt2"}) {
t.Errorf("Overriding failed : got %v", base.BuildTags)
}
- if !reflect.DeepEqual(base.Emulator, []string{"ce1", "ce2"}) {
- t.Errorf("Overriding failed : got %v", base.Emulator)
- }
if *base.AutoStackSize != false {
t.Errorf("Overriding failed : got %v", base.AutoStackSize)
}
diff --git a/main.go b/main.go
index b9b7626bf..0cb8a42c3 100644
--- a/main.go
+++ b/main.go
@@ -239,8 +239,7 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
cmd.Dir = result.MainDir
// Wasmtime needs a few extra flags to work.
- emulator := config.Emulator()
- if len(emulator) != 0 && emulator[0] == "wasmtime" {
+ if config.EmulatorName() == "wasmtime" {
// Add directories to the module root, but skip the current working
// directory which is already added by buildAndRun.
dirs := dirsToModuleRoot(result.MainDir, result.ModuleRoot)
@@ -484,18 +483,19 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
return err
}
- return builder.Build(pkgName, "", config, func(result builder.BuildResult) error {
+ format, fileExt := config.EmulatorFormat()
+ return builder.Build(pkgName, fileExt, config, func(result builder.BuildResult) error {
// Find a good way to run GDB.
gdbInterface, openocdInterface := config.Programmer()
switch gdbInterface {
case "msd", "command", "":
- emulator := config.Emulator()
- if len(emulator) != 0 {
- if emulator[0] == "mgba" {
+ emulator := config.EmulatorName()
+ if emulator != "" {
+ if emulator == "mgba" {
gdbInterface = "mgba"
- } else if emulator[0] == "simavr" {
+ } else if emulator == "simavr" {
gdbInterface = "simavr"
- } else if strings.HasPrefix(emulator[0], "qemu-system-") {
+ } else if strings.HasPrefix(emulator, "qemu-system-") {
gdbInterface = "qemu"
} else {
// Assume QEMU as an emulator.
@@ -514,6 +514,10 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
port := ""
var gdbCommands []string
var daemon *exec.Cmd
+ emulator, err := config.Emulator(format, result.Binary)
+ if err != nil {
+ return err
+ }
switch gdbInterface {
case "native":
// Run GDB directly.
@@ -563,33 +567,29 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
}
case "qemu":
port = ":1234"
- emulator := config.Emulator()
// Run in an emulator.
- args := append(emulator[1:], result.Binary, "-s", "-S")
+ args := append(emulator[1:], "-s", "-S")
daemon = executeCommand(config.Options, emulator[0], args...)
daemon.Stdout = os.Stdout
daemon.Stderr = os.Stderr
case "qemu-user":
port = ":1234"
- emulator := config.Emulator()
// Run in an emulator.
- args := append(emulator[1:], "-g", "1234", result.Binary)
+ args := append(emulator[1:], "-g", "1234")
daemon = executeCommand(config.Options, emulator[0], args...)
daemon.Stdout = os.Stdout
daemon.Stderr = os.Stderr
case "mgba":
port = ":2345"
- emulator := config.Emulator()
// Run in an emulator.
- args := append(emulator[1:], result.Binary, "-g")
+ args := append(emulator[1:], "-g")
daemon = executeCommand(config.Options, emulator[0], args...)
daemon.Stdout = os.Stdout
daemon.Stderr = os.Stderr
case "simavr":
port = ":1234"
- emulator := config.Emulator()
// Run in an emulator.
- args := append(emulator[1:], "-g", result.Binary)
+ args := append(emulator[1:], "-g")
daemon = executeCommand(config.Options, emulator[0], args...)
daemon.Stdout = os.Stdout
daemon.Stderr = os.Stderr
@@ -666,7 +666,7 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
- err := cmd.Run()
+ err = cmd.Run()
if err != nil {
return &commandError{"failed to run " + cmdName + " with", result.Binary, err}
}
@@ -694,9 +694,6 @@ func Run(pkgName string, options *compileopts.Options, cmdArgs []string) error {
// passes command line arguments and evironment variables in a way appropriate
// for the given emulator.
func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, cmdArgs, environmentVars []string, timeout time.Duration, run func(cmd *exec.Cmd, result builder.BuildResult) error) error {
- // make sure any special vars in the emulator definition are rewritten
- emulator := config.Emulator()
-
// Determine whether we're on a system that supports environment variables
// and command line parameters (operating systems, WASI) or not (baremetal,
// WebAssembly in the browser). If we're on a system without an environment,
@@ -728,7 +725,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
"runtime": runtimeGlobals,
}
}
- } else if len(emulator) != 0 && emulator[0] == "wasmtime" {
+ } else if config.EmulatorName() == "wasmtime" {
// Wasmtime needs some special flags to pass environment variables
// and allow reading from the current directory.
args = append(args, "--dir=.")
@@ -747,7 +744,8 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
env = environmentVars
}
- return builder.Build(pkgName, "", config, func(result builder.BuildResult) error {
+ format, fileExt := config.EmulatorFormat()
+ return builder.Build(pkgName, fileExt, config, func(result builder.BuildResult) error {
// If needed, set a timeout on the command. This is done in tests so
// they don't waste resources on a stalled test.
var ctx context.Context
@@ -759,12 +757,15 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
// Set up the command.
var name string
- if len(emulator) == 0 {
+ if config.Target.Emulator == "" {
name = result.Binary
} else {
+ emulator, err := config.Emulator(format, result.Binary)
+ if err != nil {
+ return err
+ }
name = emulator[0]
emuArgs := append([]string(nil), emulator[1:]...)
- emuArgs = append(emuArgs, result.Binary)
args = append(emuArgs, args...)
}
var cmd *exec.Cmd
@@ -779,7 +780,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
// stdout.
cmd.Stdout = stdout
cmd.Stderr = os.Stderr
- if len(emulator) != 0 && emulator[0] == "simavr" {
+ if config.EmulatorName() == "simavr" {
cmd.Stdout = nil // don't print initial load commands
cmd.Stderr = stdout
}
@@ -1572,7 +1573,7 @@ func main() {
os.Exit(1)
return
}
- if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == nil {
+ 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
diff --git a/main_test.go b/main_test.go
index efb4b5143..3b088ada8 100644
--- a/main_test.go
+++ b/main_test.go
@@ -223,7 +223,7 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
runTest(name, options, t, nil, nil)
})
}
- if len(spec.Emulator) == 0 || spec.Emulator[0] != "simavr" {
+ if !strings.HasPrefix(spec.Emulator, "simavr ") {
t.Run("env.go", func(t *testing.T) {
t.Parallel()
runTest("env.go", options, t, []string{"first", "second"}, []string{"ENV1=VALUE1", "ENV2=VALUE2"})
@@ -257,8 +257,8 @@ func emuCheck(t *testing.T, options compileopts.Options) {
if err != nil {
t.Fatal("failed to load target spec:", err)
}
- if len(spec.Emulator) != 0 {
- _, err := exec.LookPath(spec.Emulator[0])
+ if spec.Emulator != "" {
+ _, err := exec.LookPath(strings.SplitN(spec.Emulator, " ", 2)[0])
if err != nil {
if errors.Is(err, exec.ErrNotFound) {
t.Skipf("emulator not installed: %q", spec.Emulator[0])
@@ -327,9 +327,6 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
t.Fatal(err)
}
- // make sure any special vars in the emulator definition are rewritten
- emulator := config.Emulator()
-
// Build the test binary.
stdout := &bytes.Buffer{}
err = buildAndRun("./"+path, config, stdout, cmdArgs, environmentVars, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
@@ -345,7 +342,7 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
actual := bytes.Replace(stdout.Bytes(), []byte{'\r', '\n'}, []byte{'\n'}, -1)
expected = bytes.Replace(expected, []byte{'\r', '\n'}, []byte{'\n'}, -1) // for Windows
- if len(emulator) != 0 && emulator[0] == "simavr" {
+ if config.EmulatorName() == "simavr" {
// Strip simavr log formatting.
actual = bytes.Replace(actual, []byte{0x1b, '[', '3', '2', 'm'}, nil, -1)
actual = bytes.Replace(actual, []byte{0x1b, '[', '0', 'm'}, nil, -1)
diff --git a/targets/arduino-nano.json b/targets/arduino-nano.json
index 9f3a3b9fd..548e87b18 100644
--- a/targets/arduino-nano.json
+++ b/targets/arduino-nano.json
@@ -6,5 +6,5 @@
"-Wl,--defsym=_stack_size=512"
],
"flash-command": "avrdude -c arduino -p atmega328p -b 57600 -P {port} -U flash:w:{hex}:i",
- "emulator": ["simavr", "-m", "atmega328p", "-f", "16000000"]
+ "emulator": "simavr -m atmega328p -f 16000000 {}"
}
diff --git a/targets/arduino.json b/targets/arduino.json
index 91dc49b89..f2702304c 100644
--- a/targets/arduino.json
+++ b/targets/arduino.json
@@ -7,5 +7,5 @@
],
"flash-command": "avrdude -c arduino -p atmega328p -P {port} -U flash:w:{hex}:i",
"serial-port": ["acm:2341:0043", "acm:2341:0001", "acm:2a03:0043", "acm:2341:0243"],
- "emulator": ["simavr", "-m", "atmega328p", "-f", "16000000"]
+ "emulator": "simavr -m atmega328p -f 16000000 {}"
}
diff --git a/targets/atmega1284p.json b/targets/atmega1284p.json
index 7740ccf1c..d78d6a2a9 100644
--- a/targets/atmega1284p.json
+++ b/targets/atmega1284p.json
@@ -13,5 +13,5 @@
"targets/avr.S",
"src/device/avr/atmega1284p.s"
],
- "emulator": ["simavr", "-m", "atmega1284p", "-f", "20000000"]
+ "emulator": "simavr -m atmega1284p -f 20000000 {}"
}
diff --git a/targets/cortex-m-qemu.json b/targets/cortex-m-qemu.json
index 1d1cfc895..80e087aa5 100644
--- a/targets/cortex-m-qemu.json
+++ b/targets/cortex-m-qemu.json
@@ -5,5 +5,5 @@
"extra-files": [
"targets/cortex-m-qemu.s"
],
- "emulator": ["qemu-system-arm", "-machine", "lm3s6965evb", "-semihosting", "-nographic", "-kernel"]
+ "emulator": "qemu-system-arm -machine lm3s6965evb -semihosting -nographic -kernel {}"
}
diff --git a/targets/digispark.json b/targets/digispark.json
index 14606b044..ad9b1550c 100644
--- a/targets/digispark.json
+++ b/targets/digispark.json
@@ -6,5 +6,5 @@
"-Wl,--defsym=_stack_size=128"
],
"flash-command": "micronucleus --run {hex}",
- "emulator": ["simavr", "-m", "attiny85", "-f", "16000000"]
+ "emulator": "simavr -m attiny85 -f 16000000 {}"
}
diff --git a/targets/gameboy-advance.json b/targets/gameboy-advance.json
index 8f46c642d..0ead08313 100644
--- a/targets/gameboy-advance.json
+++ b/targets/gameboy-advance.json
@@ -24,5 +24,5 @@
"src/runtime/gc_arm.S"
],
"gdb": ["gdb-multiarch"],
- "emulator": ["mgba", "-3"]
+ "emulator": "mgba -3 {}"
}
diff --git a/targets/hifive1-qemu.json b/targets/hifive1-qemu.json
index 115189438..5d2d3143a 100644
--- a/targets/hifive1-qemu.json
+++ b/targets/hifive1-qemu.json
@@ -4,5 +4,5 @@
"serial": "uart",
"default-stack-size": 4096,
"linkerscript": "targets/hifive1-qemu.ld",
- "emulator": ["qemu-system-riscv32", "-machine", "sifive_e", "-nographic", "-kernel"]
+ "emulator": "qemu-system-riscv32 -machine sifive_e -nographic -kernel {}"
}
diff --git a/targets/riscv-qemu.json b/targets/riscv-qemu.json
index ebc220e97..84050ff6c 100644
--- a/targets/riscv-qemu.json
+++ b/targets/riscv-qemu.json
@@ -4,5 +4,5 @@
"build-tags": ["virt", "qemu"],
"default-stack-size": 4096,
"linkerscript": "targets/riscv-qemu.ld",
- "emulator": ["qemu-system-riscv32", "-machine", "virt", "-nographic", "-bios", "none", "-kernel"]
+ "emulator": "qemu-system-riscv32 -machine virt -nographic -bios none -kernel {}"
}
diff --git a/targets/wasi.json b/targets/wasi.json
index 9ae96a338..8ff4c3a26 100644
--- a/targets/wasi.json
+++ b/targets/wasi.json
@@ -13,6 +13,6 @@
"--stack-first",
"--no-demangle"
],
- "emulator": ["wasmtime"],
+ "emulator": "wasmtime {}",
"wasm-abi": "generic"
}
diff --git a/targets/wasm.json b/targets/wasm.json
index 12857dc13..1cc3410d7 100644
--- a/targets/wasm.json
+++ b/targets/wasm.json
@@ -13,6 +13,6 @@
"--stack-first",
"--no-demangle"
],
- "emulator": ["node", "{root}/targets/wasm_exec.js"],
+ "emulator": "node {root}/targets/wasm_exec.js {}",
"wasm-abi": "js"
}