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.
Этот коммит содержится в:
родитель
4fe3a379a5
коммит
bd56636d58
15 изменённых файлов: 82 добавлений и 74 удалений
|
@ -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 {
|
||||
var emulator []string
|
||||
for _, s := range c.Target.Emulator {
|
||||
emulator = append(emulator, strings.ReplaceAll(s, "{root}", goenv.Get("TINYGOROOT")))
|
||||
// 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 emulator
|
||||
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 parts {
|
||||
s = strings.ReplaceAll(s, "{root}", goenv.Get("TINYGOROOT"))
|
||||
s = strings.ReplaceAll(s, "{"+format+"}", binary)
|
||||
emulator = append(emulator, s)
|
||||
}
|
||||
return emulator, nil
|
||||
}
|
||||
|
||||
type TestConfig struct {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
53
main.go
53
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
|
||||
|
|
11
main_test.go
11
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)
|
||||
|
|
|
@ -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 {}"
|
||||
}
|
||||
|
|
|
@ -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 {}"
|
||||
}
|
||||
|
|
|
@ -13,5 +13,5 @@
|
|||
"targets/avr.S",
|
||||
"src/device/avr/atmega1284p.s"
|
||||
],
|
||||
"emulator": ["simavr", "-m", "atmega1284p", "-f", "20000000"]
|
||||
"emulator": "simavr -m atmega1284p -f 20000000 {}"
|
||||
}
|
||||
|
|
|
@ -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 {}"
|
||||
}
|
||||
|
|
|
@ -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 {}"
|
||||
}
|
||||
|
|
|
@ -24,5 +24,5 @@
|
|||
"src/runtime/gc_arm.S"
|
||||
],
|
||||
"gdb": ["gdb-multiarch"],
|
||||
"emulator": ["mgba", "-3"]
|
||||
"emulator": "mgba -3 {}"
|
||||
}
|
||||
|
|
|
@ -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 {}"
|
||||
}
|
||||
|
|
|
@ -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 {}"
|
||||
}
|
||||
|
|
|
@ -13,6 +13,6 @@
|
|||
"--stack-first",
|
||||
"--no-demangle"
|
||||
],
|
||||
"emulator": ["wasmtime"],
|
||||
"emulator": "wasmtime {}",
|
||||
"wasm-abi": "generic"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче