Skip to content

Commit 15e37ff

Browse files
rdon-keyrdon
andauthored
flash: add -o flag support to save built binary (Fixes #4937) (#4942)
* Add -o flag support to flash command. Fixes #4937 * Remove empty outpath check in validateOutputFormat --------- Co-authored-by: rdon <[email protected]>
1 parent 9123406 commit 15e37ff

File tree

1 file changed

+29
-4
lines changed

1 file changed

+29
-4
lines changed

main.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,17 @@ func dirsToModuleRootAbs(maindir, modroot string) []string {
340340
return dirs
341341
}
342342

343+
// validateOutputFormat checks if the output file extension matches the expected format
344+
func validateOutputFormat(outpath, expectedExt string) error {
345+
actualExt := filepath.Ext(outpath)
346+
if actualExt != expectedExt {
347+
return fmt.Errorf("output format %s does not match target format %s", actualExt, expectedExt)
348+
}
349+
return nil
350+
}
351+
343352
// Flash builds and flashes the built binary to the given serial port.
344-
func Flash(pkgName, port string, options *compileopts.Options) error {
353+
func Flash(pkgName, port, outpath string, options *compileopts.Options) error {
345354
config, err := builder.NewConfig(options)
346355
if err != nil {
347356
return err
@@ -390,13 +399,24 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
390399
if !options.Work {
391400
defer os.RemoveAll(tmpdir)
392401
}
393-
402+
// Validate output format before building
403+
if outpath != "" {
404+
if err := validateOutputFormat(outpath, fileExt); err != nil {
405+
return err
406+
}
407+
}
394408
// Build the binary.
395409
result, err := builder.Build(pkgName, fileExt, tmpdir, config)
396410
if err != nil {
397411
return err
398412
}
399413

414+
// Save output file if specified (after build, before flashing)
415+
if outpath != "" {
416+
if err := copyFile(result.Binary, outpath); err != nil {
417+
return fmt.Errorf("failed to save output file: %v", err)
418+
}
419+
}
400420
// do we need port reset to put MCU into bootloader mode?
401421
if config.Target.PortReset == "true" && flashMethod != "openocd" {
402422
port, err := getDefaultPort(port, config.Target.SerialPort)
@@ -1298,6 +1318,11 @@ extension at all.`
12981318
(https://tinygo.org/docs/reference/microcontrollers/).
12991319
Examples: "arduino-nano", "d1mini", "xiao".
13001320
1321+
-o={filename}:
1322+
Save the built binary to the specified output file. The file
1323+
format must match the target's expected format (e.g., .hex,
1324+
.uf2). Both flashing and saving will be performed.
1325+
13011326
-monitor:
13021327
Start the serial monitor (see below) immediately after
13031328
flashing. However, some microcontrollers need a split second
@@ -1628,7 +1653,7 @@ func main() {
16281653
flag.BoolVar(&flagTest, "test", false, "supply -test flag to go list")
16291654
}
16301655
var outpath string
1631-
if command == "help" || command == "build" || command == "test" {
1656+
if command == "help" || command == "build" || command == "test" || command == "flash" {
16321657
flag.StringVar(&outpath, "o", "", "output filename")
16331658
}
16341659

@@ -1779,7 +1804,7 @@ func main() {
17791804
case "flash", "gdb", "lldb":
17801805
pkgName := filepath.ToSlash(flag.Arg(0))
17811806
if command == "flash" {
1782-
err := Flash(pkgName, *port, options)
1807+
err := Flash(pkgName, *port, outpath, options)
17831808
printBuildOutput(err, *flagJSON)
17841809
} else {
17851810
if !options.Debug {

0 commit comments

Comments
 (0)