@@ -340,8 +340,17 @@ func dirsToModuleRootAbs(maindir, modroot string) []string {
340
340
return dirs
341
341
}
342
342
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
+
343
352
// 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 {
345
354
config , err := builder .NewConfig (options )
346
355
if err != nil {
347
356
return err
@@ -390,13 +399,24 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
390
399
if ! options .Work {
391
400
defer os .RemoveAll (tmpdir )
392
401
}
393
-
402
+ // Validate output format before building
403
+ if outpath != "" {
404
+ if err := validateOutputFormat (outpath , fileExt ); err != nil {
405
+ return err
406
+ }
407
+ }
394
408
// Build the binary.
395
409
result , err := builder .Build (pkgName , fileExt , tmpdir , config )
396
410
if err != nil {
397
411
return err
398
412
}
399
413
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
+ }
400
420
// do we need port reset to put MCU into bootloader mode?
401
421
if config .Target .PortReset == "true" && flashMethod != "openocd" {
402
422
port , err := getDefaultPort (port , config .Target .SerialPort )
@@ -1298,6 +1318,11 @@ extension at all.`
1298
1318
(https://tinygo.org/docs/reference/microcontrollers/).
1299
1319
Examples: "arduino-nano", "d1mini", "xiao".
1300
1320
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
+
1301
1326
-monitor:
1302
1327
Start the serial monitor (see below) immediately after
1303
1328
flashing. However, some microcontrollers need a split second
@@ -1628,7 +1653,7 @@ func main() {
1628
1653
flag .BoolVar (& flagTest , "test" , false , "supply -test flag to go list" )
1629
1654
}
1630
1655
var outpath string
1631
- if command == "help" || command == "build" || command == "test" {
1656
+ if command == "help" || command == "build" || command == "test" || command == "flash" {
1632
1657
flag .StringVar (& outpath , "o" , "" , "output filename" )
1633
1658
}
1634
1659
@@ -1779,7 +1804,7 @@ func main() {
1779
1804
case "flash" , "gdb" , "lldb" :
1780
1805
pkgName := filepath .ToSlash (flag .Arg (0 ))
1781
1806
if command == "flash" {
1782
- err := Flash (pkgName , * port , options )
1807
+ err := Flash (pkgName , * port , outpath , options )
1783
1808
printBuildOutput (err , * flagJSON )
1784
1809
} else {
1785
1810
if ! options .Debug {
0 commit comments