diff --git a/builder/build.go b/builder/build.go index f17d26c72..e7c4b8094 100644 --- a/builder/build.go +++ b/builder/build.go @@ -100,7 +100,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil AutomaticStackSize: config.AutomaticStackSize(), DefaultStackSize: config.Target.DefaultStackSize, NeedsStackObjects: config.NeedsStackObjects(), - Debug: config.Debug(), + Debug: config.EmitDWARF(), LLVMFeatures: config.LLVMFeatures(), } @@ -537,6 +537,41 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil ldflags = append(ldflags, lprogram.LDFlags...) } + // Strip debug information if -debug is true. This is sometimes the default, + // such as with WebAssembly targets. + if !config.Debug() { + for _, tag := range config.BuildTags() { + if tag == "baremetal" { + // Don't use -debug=false on baremetal targets. It makes no + // sense: the debug information isn't flashed to the device + // anyway. + return fmt.Errorf("stripping debug information is unnecessary for baremetal targets") + } + } + if config.Target.Linker == "wasm-ld" { + // Don't just strip debug information, also compress relocations + // while we're at it. Relocations can only be compressed when debug + // information is stripped. + ldflags = append(ldflags, "--strip-debug", "--compress-relocations") + } else { + switch config.GOOS() { + case "linux": + // Either real linux or an embedded system (like AVR) that + // pretends to be Linux. It's a ELF linker wrapped by GCC in any + // case. + ldflags = append(ldflags, "-Wl,--strip-debug") + case "darwin": + // MacOS (darwin) doesn't have a linker flag to strip debug + // information. Apple expects you to use the strip command + // instead. + return errors.New("cannot remove debug information: MacOS doesn't suppor this linker flag") + default: + // Other OSes may have different flags. + return errors.New("cannot remove debug information: unknown OS: " + config.GOOS()) + } + } + } + // Create a linker job, which links all object files together and does some // extra stuff that can only be done after linking. jobs = append(jobs, &compileJob{ diff --git a/compileopts/config.go b/compileopts/config.go index a60f778e0..ea21221b6 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -209,7 +209,7 @@ func (c *Config) CFlags() []string { cflags = append(cflags, "-nostdlibinc", "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "picolibc", "newlib", "libc", "include")) cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include")) } - if c.Debug() { + if c.EmitDWARF() { cflags = append(cflags, "-g") } return cflags @@ -250,10 +250,33 @@ func (c *Config) VerifyIR() bool { return c.Options.VerifyIR } -// Debug returns whether to add debug symbols to the IR, for debugging with GDB -// and similar. +// EmitDWARF returns whether to add debug symbols to the IR, for debugging with +// GDB and similar. +func (c *Config) EmitDWARF() bool { + return c.Options.EmitDWARF +} + +// Debug returns whether debug (DWARF) information should be retained by the +// linker. The default varies by target but can be controlled with the -debug +// command line flag. func (c *Config) Debug() bool { - return c.Options.Debug + switch c.Options.Debug { + case "true": + return true + case "false": + return false + case "auto": + // Emit debug information everywhere by default except on WebAssembly. + for _, tag := range c.BuildTags() { + if tag == "tinygo.wasm" { + return false + } + } + return true + default: + // This is already checked so shouldn't happen. + panic("unknown -debug flag") + } } // BinaryFormat returns an appropriate binary format, based on the file diff --git a/compileopts/options.go b/compileopts/options.go index 7e7bfcafc..2babd19d8 100644 --- a/compileopts/options.go +++ b/compileopts/options.go @@ -9,6 +9,7 @@ import ( var ( validGCOptions = []string{"none", "leaking", "extalloc", "conservative"} validSchedulerOptions = []string{"none", "tasks", "coroutines"} + validDebugOptions = []string{"auto", "true", "false"} validSerialOptions = []string{"none", "uart", "usb"} validPrintSizeOptions = []string{"none", "short", "full"} validPanicStrategyOptions = []string{"print", "trap"} @@ -28,7 +29,8 @@ type Options struct { DumpSSA bool VerifyIR bool PrintCommands func(cmd string, args ...string) - Debug bool + EmitDWARF bool + Debug string PrintSizes string PrintAllocs *regexp.Regexp // regexp string PrintStacks bool @@ -70,6 +72,12 @@ func (o *Options) Verify() error { } } + if !isInArray(validDebugOptions, o.Debug) { + return fmt.Errorf(`invalid debug option '%s': valid values are %s`, + o.Debug, + strings.Join(validDebugOptions, ", ")) + } + if o.PrintSizes != "" { valid := isInArray(validPrintSizeOptions, o.PrintSizes) if !valid { diff --git a/main.go b/main.go index 7c3ee96df..e0eb58070 100644 --- a/main.go +++ b/main.go @@ -1019,6 +1019,7 @@ func main() { printStacks := flag.Bool("print-stacks", false, "print stack sizes of goroutines") printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed") printCommands := flag.Bool("x", false, "Print commands") + debug := flag.String("debug", "auto", "remove debug information (auto, true, false)") nodebug := flag.Bool("no-debug", false, "disable DWARF debug symbol generation") ocdCommandsString := flag.String("ocd-commands", "", "OpenOCD commands, overriding target spec (can specify multiple separated by commas)") ocdOutput := flag.Bool("ocd-output", false, "print OCD daemon output during debug") @@ -1086,7 +1087,8 @@ func main() { PrintIR: *printIR, DumpSSA: *dumpSSA, VerifyIR: *verifyIR, - Debug: !*nodebug, + EmitDWARF: !*nodebug, + Debug: *debug, PrintSizes: *printSize, PrintStacks: *printStacks, PrintAllocs: printAllocs, @@ -1173,7 +1175,7 @@ func main() { err := Flash(pkgName, *port, options) handleCompilerError(err) } else { - if !options.Debug { + if !options.EmitDWARF { fmt.Fprintln(os.Stderr, "Debug disabled while running gdb?") usage() os.Exit(1) diff --git a/main_test.go b/main_test.go index 51fd21fd2..9cabf0f73 100644 --- a/main_test.go +++ b/main_test.go @@ -194,7 +194,7 @@ func runTest(name, target string, t *testing.T, cmdArgs, environmentVars []strin PrintIR: false, DumpSSA: false, VerifyIR: true, - Debug: true, + EmitDWARF: true, PrintSizes: "", WasmAbi: "", }