test output format for all target/emuator/flash-method

This commit is contained in:
Li Jie
2025-09-06 18:58:43 +08:00
parent 7cad146013
commit 549beeb101
5 changed files with 335 additions and 41 deletions

View File

@@ -52,6 +52,7 @@ type Cmd_version struct {
xcmd.Command
*App
}
//line cmd/llgo/main_app.gox:1
func (this *App) MainEntry() {
//line cmd/llgo/main_app.gox:1:1
@@ -68,6 +69,7 @@ func (this *App) Main() {
_xgo_obj7 := &Cmd_version{App: this}
xcmd.Gopt_App_Main(this, _xgo_obj0, _xgo_obj1, _xgo_obj2, _xgo_obj3, _xgo_obj4, _xgo_obj5, _xgo_obj6, _xgo_obj7)
}
//line cmd/llgo/build_cmd.gox:20
func (this *Cmd_build) Main(_xgo_arg0 string) {
this.Command.Main(_xgo_arg0)
@@ -86,6 +88,7 @@ func (this *Cmd_build) Main(_xgo_arg0 string) {
func (this *Cmd_build) Classfname() string {
return "build"
}
//line cmd/llgo/clean_cmd.gox:20
func (this *Cmd_clean) Main(_xgo_arg0 string) {
this.Command.Main(_xgo_arg0)
@@ -104,6 +107,7 @@ func (this *Cmd_clean) Main(_xgo_arg0 string) {
func (this *Cmd_clean) Classfname() string {
return "clean"
}
//line cmd/llgo/cmptest_cmd.gox:20
func (this *Cmd_cmptest) Main(_xgo_arg0 string) {
this.Command.Main(_xgo_arg0)
@@ -122,6 +126,7 @@ func (this *Cmd_cmptest) Main(_xgo_arg0 string) {
func (this *Cmd_cmptest) Classfname() string {
return "cmptest"
}
//line cmd/llgo/get_cmd.gox:16
func (this *Cmd_get) Main(_xgo_arg0 string) {
this.Command.Main(_xgo_arg0)
@@ -138,6 +143,7 @@ func (this *Cmd_get) Main(_xgo_arg0 string) {
func (this *Cmd_get) Classfname() string {
return "get"
}
//line cmd/llgo/install_cmd.gox:20
func (this *Cmd_install) Main(_xgo_arg0 string) {
this.Command.Main(_xgo_arg0)
@@ -156,6 +162,7 @@ func (this *Cmd_install) Main(_xgo_arg0 string) {
func (this *Cmd_install) Classfname() string {
return "install"
}
//line cmd/llgo/run_cmd.gox:20
func (this *Cmd_run) Main(_xgo_arg0 string) {
this.Command.Main(_xgo_arg0)
@@ -174,6 +181,7 @@ func (this *Cmd_run) Main(_xgo_arg0 string) {
func (this *Cmd_run) Classfname() string {
return "run"
}
//line cmd/llgo/test_cmd.gox:20
func (this *Cmd_test) Main(_xgo_arg0 string) {
this.Command.Main(_xgo_arg0)
@@ -192,6 +200,7 @@ func (this *Cmd_test) Main(_xgo_arg0 string) {
func (this *Cmd_test) Classfname() string {
return "test"
}
//line cmd/llgo/version_cmd.gox:22
func (this *Cmd_version) Main(_xgo_arg0 string) {
this.Command.Main(_xgo_arg0)

View File

@@ -315,9 +315,8 @@ func Do(args []string, conf *Config) ([]Package, error) {
for _, pkg := range initial {
if needLink(pkg, mode) {
name := path.Base(pkg.PkgPath)
binFmt := ctx.crossCompile.BinaryFormat
outputCfg, err := genOutputs(conf, name, len(ctx.initial) > 1, ctx.crossCompile.Emulator, binFmt)
outputCfg, err := genOutputs(conf, name, len(ctx.initial) > 1, &ctx.crossCompile)
if err != nil {
return nil, err
}

View File

@@ -3,7 +3,9 @@ package build
import (
"os"
"path/filepath"
"strings"
"github.com/goplus/llgo/internal/crosscompile"
"github.com/goplus/llgo/internal/firmware"
)
@@ -19,15 +21,16 @@ type OutputCfg struct {
}
// genOutputs generates appropriate output paths based on the configuration
func genOutputs(conf *Config, pkgName string, multiPkg bool, emulator, binFmt string) (OutputCfg, error) {
func genOutputs(conf *Config, pkgName string, multiPkg bool, crossCompile *crosscompile.Export) (OutputCfg, error) {
var cfg OutputCfg
// Calculate binary extension and set up format info
binFmt := crossCompile.BinaryFormat
binExt := firmware.BinaryExt(binFmt)
cfg.BinFmt = binFmt
// Determine output format and extension
cfg.FileFmt, cfg.OutExt = determineFormat(conf, emulator)
cfg.FileFmt, cfg.OutExt = determineFormat(conf, crossCompile)
// Handle special .img case and set conversion flags
cfg.DirectGen = shouldDirectGen(cfg.OutExt, binExt)
@@ -52,22 +55,70 @@ func genOutputs(conf *Config, pkgName string, multiPkg bool, emulator, binFmt st
}
// determineFormat determines the file format and extension
func determineFormat(conf *Config, emulator string) (format, ext string) {
func determineFormat(conf *Config, crossCompile *crosscompile.Export) (format, ext string) {
if conf.FileFormat != "" {
// User specified file format
return conf.FileFormat, firmware.GetFileExtFromFormat(conf.FileFormat)
}
if conf.Mode == ModeRun && conf.Emulator && emulator != "" {
if conf.Mode == ModeRun && conf.Emulator && crossCompile.Emulator != "" {
// Emulator mode - extract format from emulator command
if emulatorFmt := firmware.ExtractFileFormatFromEmulator(emulator); emulatorFmt != "" {
if emulatorFmt := firmware.ExtractFileFormatFromEmulator(crossCompile.Emulator); emulatorFmt != "" {
return emulatorFmt, firmware.GetFileExtFromFormat(emulatorFmt)
}
}
// Device flashing - determine format based on flash method and target
if conf.Target != "" && (conf.Mode == ModeInstall || conf.Mode == ModeRun || conf.Mode == ModeTest || conf.Mode == ModeCmpTest) {
if flashExt := determineFlashFormat(crossCompile); flashExt != "" {
return flashExt[1:], flashExt // Remove the dot for format, keep for ext
}
}
return "", ""
}
// determineFlashFormat determines the required file format for flashing based on flash method
func determineFlashFormat(crossCompile *crosscompile.Export) string {
if crossCompile == nil {
return ""
}
flashMethod := crossCompile.Flash.Method
switch flashMethod {
case "command", "":
// Extract format from flash command tokens
flashCommand := crossCompile.Flash.Command
switch {
case strings.Contains(flashCommand, "{hex}"):
return ".hex"
case strings.Contains(flashCommand, "{elf}"):
return ".elf"
case strings.Contains(flashCommand, "{bin}"):
return ".bin"
case strings.Contains(flashCommand, "{uf2}"):
return ".uf2"
case strings.Contains(flashCommand, "{zip}"):
return ".zip"
case strings.Contains(flashCommand, "{img}"):
return ".img"
default:
return ""
}
case "msd":
if crossCompile.MSD.FirmwareName == "" {
return ""
}
return filepath.Ext(crossCompile.MSD.FirmwareName)
case "openocd":
return ".hex"
case "bmp":
return ".elf"
default:
return ""
}
}
// shouldDirectGen determines if direct firmware generation is possible
func shouldDirectGen(outExt, binExt string) bool {
return outExt == "" || outExt == binExt || outExt == ".img"

View File

@@ -5,6 +5,8 @@ package build
import (
"testing"
"github.com/goplus/llgo/internal/crosscompile"
)
func TestGenOutputs(t *testing.T) {
@@ -13,7 +15,7 @@ func TestGenOutputs(t *testing.T) {
conf *Config
pkgName string
multiPkg bool
emulator string
crossCompile *crosscompile.Export
wantOutPath string // use empty string to indicate temp file
wantIntPath string // use empty string to indicate same as outPath
wantOutExt string
@@ -28,7 +30,10 @@ func TestGenOutputs(t *testing.T) {
BinPath: "/go/bin",
AppExt: "",
},
pkgName: "hello",
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "",
},
wantOutPath: "hello",
wantOutExt: "",
wantFileFmt: "",
@@ -42,7 +47,10 @@ func TestGenOutputs(t *testing.T) {
OutFile: "myapp",
AppExt: "",
},
pkgName: "hello",
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "",
},
wantOutPath: "myapp",
wantOutExt: "",
wantFileFmt: "",
@@ -58,7 +66,10 @@ func TestGenOutputs(t *testing.T) {
FileFormat: "bin",
Target: "esp32",
},
pkgName: "hello",
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "esp32",
},
wantOutPath: "hello.bin",
wantOutExt: ".bin",
wantFileFmt: "bin",
@@ -74,7 +85,10 @@ func TestGenOutputs(t *testing.T) {
FileFormat: "hex",
Target: "esp32",
},
pkgName: "hello",
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "esp32",
},
wantOutPath: "myapp.hex",
wantOutExt: ".hex",
wantFileFmt: "hex",
@@ -90,7 +104,10 @@ func TestGenOutputs(t *testing.T) {
FileFormat: "hex",
Target: "esp32",
},
pkgName: "hello",
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "esp32",
},
wantOutPath: "myapp.hex",
wantOutExt: ".hex",
wantFileFmt: "hex",
@@ -103,7 +120,10 @@ func TestGenOutputs(t *testing.T) {
Mode: ModeRun,
AppExt: "",
},
pkgName: "hello",
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "",
},
wantOutPath: "", // temp file
wantOutExt: "",
wantFileFmt: "",
@@ -117,7 +137,10 @@ func TestGenOutputs(t *testing.T) {
AppExt: "",
Target: "esp32",
},
pkgName: "hello",
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "esp32",
},
wantOutPath: "", // temp file
wantOutExt: "",
wantFileFmt: "",
@@ -132,8 +155,11 @@ func TestGenOutputs(t *testing.T) {
Target: "esp32",
Emulator: true,
},
pkgName: "hello",
emulator: "qemu-system-xtensa -machine esp32 -drive file={hex},if=mtd,format=raw",
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "esp32",
Emulator: "qemu-system-xtensa -machine esp32 -drive file={hex},if=mtd,format=raw",
},
wantOutPath: "", // temp file
wantOutExt: ".hex",
wantFileFmt: "hex",
@@ -149,7 +175,10 @@ func TestGenOutputs(t *testing.T) {
FileFormat: "img",
Target: "esp32",
},
pkgName: "hello",
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "esp32",
},
wantOutPath: "hello.img",
wantOutExt: ".img",
wantFileFmt: "img",
@@ -162,7 +191,10 @@ func TestGenOutputs(t *testing.T) {
Mode: ModeTest,
AppExt: "",
},
pkgName: "hello",
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "",
},
wantOutPath: "", // temp file
wantOutExt: "",
wantFileFmt: "",
@@ -176,7 +208,10 @@ func TestGenOutputs(t *testing.T) {
AppExt: "",
Target: "esp32",
},
pkgName: "hello",
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "esp32",
},
wantOutPath: "", // temp file
wantOutExt: "",
wantFileFmt: "",
@@ -189,7 +224,10 @@ func TestGenOutputs(t *testing.T) {
Mode: ModeCmpTest,
AppExt: "",
},
pkgName: "hello",
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "",
},
wantOutPath: "", // temp file
wantOutExt: "",
wantFileFmt: "",
@@ -203,7 +241,10 @@ func TestGenOutputs(t *testing.T) {
BinPath: "/go/bin",
AppExt: "",
},
pkgName: "hello",
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "",
},
wantOutPath: "/go/bin/hello",
wantOutExt: "",
wantFileFmt: "",
@@ -218,7 +259,10 @@ func TestGenOutputs(t *testing.T) {
AppExt: "",
Target: "esp32",
},
pkgName: "hello",
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "esp32",
},
wantOutPath: "", // temp file for flashing
wantOutExt: "",
wantFileFmt: "",
@@ -234,13 +278,138 @@ func TestGenOutputs(t *testing.T) {
FileFormat: "hex",
Target: "esp32",
},
pkgName: "hello",
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "esp32",
},
wantOutPath: "", // temp file for flashing
wantOutExt: ".hex",
wantFileFmt: "hex",
wantBinFmt: "esp32",
wantDirectGen: false,
},
{
name: "run with target non-emulator (should use .bin from binary format)",
conf: &Config{
Mode: ModeRun,
AppExt: "",
Target: "esp32",
},
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "esp32",
},
wantOutPath: "", // temp file
wantOutExt: "",
wantFileFmt: "",
wantBinFmt: "esp32",
wantDirectGen: true,
},
{
name: "run with flash method command - extract hex from command",
conf: &Config{
Mode: ModeRun,
AppExt: "",
Target: "esp32",
},
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "esp32",
Flash: crosscompile.Flash{
Method: "command",
Command: "esptool.py --chip esp32 write_flash 0x10000 {hex}",
},
},
wantOutPath: "", // temp file
wantOutExt: ".hex",
wantFileFmt: "hex",
wantBinFmt: "esp32",
wantDirectGen: false,
},
{
name: "run with flash method command - extract bin from command",
conf: &Config{
Mode: ModeRun,
AppExt: "",
Target: "esp32",
},
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "esp32",
Flash: crosscompile.Flash{
Method: "command",
Command: "esptool.py --chip esp32 write_flash 0x10000 {bin}",
},
},
wantOutPath: "", // temp file
wantOutExt: ".bin",
wantFileFmt: "bin",
wantBinFmt: "esp32",
wantDirectGen: true,
},
{
name: "run with flash method openocd - should use .hex",
conf: &Config{
Mode: ModeRun,
AppExt: "",
Target: "stm32",
},
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "arm",
Flash: crosscompile.Flash{
Method: "openocd",
},
},
wantOutPath: "", // temp file
wantOutExt: ".hex",
wantFileFmt: "hex",
wantBinFmt: "arm",
wantDirectGen: false,
},
{
name: "run with flash method msd - extract extension from firmware name",
conf: &Config{
Mode: ModeRun,
AppExt: "",
Target: "rp2040",
},
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "uf2",
Flash: crosscompile.Flash{
Method: "msd",
},
MSD: crosscompile.MSD{
FirmwareName: "firmware.uf2",
},
},
wantOutPath: "", // temp file
wantOutExt: ".uf2",
wantFileFmt: "uf2",
wantBinFmt: "uf2",
wantDirectGen: true,
},
{
name: "run with flash method bmp - should use .elf",
conf: &Config{
Mode: ModeRun,
AppExt: "",
Target: "stm32",
},
pkgName: "hello",
crossCompile: &crosscompile.Export{
BinaryFormat: "arm",
Flash: crosscompile.Flash{
Method: "bmp",
},
},
wantOutPath: "", // temp file
wantOutExt: ".elf",
wantFileFmt: "elf",
wantBinFmt: "arm",
wantDirectGen: false,
},
}
for _, tt := range tests {
@@ -315,36 +484,100 @@ func TestGenOutputs(t *testing.T) {
func TestDetermineFormat(t *testing.T) {
tests := []struct {
name string
conf *Config
emulator string
wantFmt string
wantExt string
name string
conf *Config
crossCompile *crosscompile.Export
wantFmt string
wantExt string
}{
{
name: "user specified format",
conf: &Config{FileFormat: "hex"},
name: "user specified format",
conf: &Config{FileFormat: "hex"},
crossCompile: &crosscompile.Export{},
wantFmt: "hex",
wantExt: ".hex",
},
{
name: "emulator format extraction",
conf: &Config{Mode: ModeRun, Emulator: true},
crossCompile: &crosscompile.Export{
Emulator: "qemu-system-xtensa -machine esp32 -drive file={bin},if=mtd,format=raw",
},
wantFmt: "bin",
wantExt: ".bin",
},
{
name: "flash method command - extract hex",
conf: &Config{Mode: ModeRun, Target: "esp32"},
crossCompile: &crosscompile.Export{
Flash: crosscompile.Flash{
Method: "command",
Command: "esptool.py --chip esp32 write_flash 0x10000 {hex}",
},
},
wantFmt: "hex",
wantExt: ".hex",
},
{
name: "emulator format extraction",
conf: &Config{Mode: ModeRun, Emulator: true},
emulator: "qemu-system-xtensa -machine esp32 -drive file={bin},if=mtd,format=raw",
wantFmt: "bin",
wantExt: ".bin",
name: "flash method command - extract bin",
conf: &Config{Mode: ModeRun, Target: "esp32"},
crossCompile: &crosscompile.Export{
Flash: crosscompile.Flash{
Method: "command",
Command: "esptool.py --chip esp32 write_flash 0x10000 {bin}",
},
},
wantFmt: "bin",
wantExt: ".bin",
},
{
name: "no format",
conf: &Config{},
wantFmt: "",
wantExt: "",
name: "flash method openocd",
conf: &Config{Mode: ModeRun, Target: "stm32"},
crossCompile: &crosscompile.Export{
Flash: crosscompile.Flash{
Method: "openocd",
},
},
wantFmt: "hex",
wantExt: ".hex",
},
{
name: "flash method msd - extract from firmware name",
conf: &Config{Mode: ModeRun, Target: "rp2040"},
crossCompile: &crosscompile.Export{
Flash: crosscompile.Flash{
Method: "msd",
},
MSD: crosscompile.MSD{
FirmwareName: "firmware.uf2",
},
},
wantFmt: "uf2",
wantExt: ".uf2",
},
{
name: "flash method bmp",
conf: &Config{Mode: ModeRun, Target: "stm32"},
crossCompile: &crosscompile.Export{
Flash: crosscompile.Flash{
Method: "bmp",
},
},
wantFmt: "elf",
wantExt: ".elf",
},
{
name: "no format",
conf: &Config{},
crossCompile: &crosscompile.Export{},
wantFmt: "",
wantExt: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotFmt, gotExt := determineFormat(tt.conf, tt.emulator)
gotFmt, gotExt := determineFormat(tt.conf, tt.crossCompile)
if gotFmt != tt.wantFmt {
t.Errorf("determineFormat() format = %v, want %v", gotFmt, tt.wantFmt)
}

View File

@@ -18,6 +18,7 @@ import (
// Flash contains configuration for device flashing
type Flash struct {
Method string // Flash method: "command", "openocd", "msd", "bmp"
Command string // Flash command template
Serial string // Serial communication settings
SerialPort []string // Available serial ports
@@ -530,6 +531,7 @@ func useTarget(targetName string) (export Export, err error) {
// Set flashing/debugging configuration
export.Flash = Flash{
Method: config.FlashMethod,
Command: config.FlashCommand,
Serial: config.Serial,
SerialPort: config.SerialPort,