Skip to content

flash: add -o flag support to save built binary (Fixes #4937) #4942

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 33 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,8 +339,21 @@ func dirsToModuleRootAbs(maindir, modroot string) []string {
return dirs
}

// validateOutputFormat checks if the output file extension matches the expected format
func validateOutputFormat(outpath, expectedExt string) error {
if outpath == "" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your code checks for this condition already before calling this function, so this seems redundant

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. That check is indeed redundant since we validate outpath before calling this function. I cleaned this up.

return nil // no output file specified
}

actualExt := filepath.Ext(outpath)
if actualExt != expectedExt {
return fmt.Errorf("output format %s does not match target format %s", actualExt, expectedExt)
}
return nil
}

// Flash builds and flashes the built binary to the given serial port.
func Flash(pkgName, port string, options *compileopts.Options) error {
func Flash(pkgName, port, outpath string, options *compileopts.Options) error {
config, err := builder.NewConfig(options)
if err != nil {
return err
Expand Down Expand Up @@ -389,13 +402,24 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
if !options.Work {
defer os.RemoveAll(tmpdir)
}

// Validate output format before building
if outpath != "" {
if err := validateOutputFormat(outpath, fileExt); err != nil {
return err
}
}
// Build the binary.
result, err := builder.Build(pkgName, fileExt, tmpdir, config)
if err != nil {
return err
}

// Save output file if specified (after build, before flashing)
if outpath != "" {
if err := copyFile(result.Binary, outpath); err != nil {
return fmt.Errorf("failed to save output file: %v", err)
}
}
// do we need port reset to put MCU into bootloader mode?
if config.Target.PortReset == "true" && flashMethod != "openocd" {
port, err := getDefaultPort(port, config.Target.SerialPort)
Expand Down Expand Up @@ -1297,6 +1321,11 @@ extension at all.`
(https://tinygo.org/docs/reference/microcontrollers/).
Examples: "arduino-nano", "d1mini", "xiao".

-o={filename}:
Save the built binary to the specified output file. The file
format must match the target's expected format (e.g., .hex,
.uf2). Both flashing and saving will be performed.

-monitor:
Start the serial monitor (see below) immediately after
flashing. However, some microcontrollers need a split second
Expand Down Expand Up @@ -1627,7 +1656,7 @@ func main() {
flag.BoolVar(&flagTest, "test", false, "supply -test flag to go list")
}
var outpath string
if command == "help" || command == "build" || command == "test" {
if command == "help" || command == "build" || command == "test" || command == "flash" {
flag.StringVar(&outpath, "o", "", "output filename")
}

Expand Down Expand Up @@ -1778,7 +1807,7 @@ func main() {
case "flash", "gdb", "lldb":
pkgName := filepath.ToSlash(flag.Arg(0))
if command == "flash" {
err := Flash(pkgName, *port, options)
err := Flash(pkgName, *port, outpath, options)
printBuildOutput(err, *flagJSON)
} else {
if !options.Debug {
Expand Down