@@ -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