I build my Go project with the -N and -l options, but they only seem to apply to the top-most package -- imported packages are still optimized. From what I can tell, this is because go build isn't propagating the options that disable optimization as it tracks down and builds dependencies.
I claim that:
- If I tell go build to disable optimizations, it makes sense that optimizations should be disabled for everything it ends up building.
- Therefore, this is a bug.
I'm writing here because I'm a Go n00b, and there may be something I'm missing.
Let me show my evidence...
Consider the following trivial Go project:
.
├── main.go
└── help
└── help.go
Here's main.go:
package main
import "./help"
func main() {
help.Help()
}
Here's help.go:
package help
import "fmt"
func Help() {
fmt.Println("I'm helping")
}
Here's how I built the project:
go build -gcflags="-N -l" main.go
The -N option disables optimization, and the -l option disables inlining.
This produced an executable called main in my current directory (as expected). I tried to debug this executable with delve and saw this:
$ dlv exec main
Type 'help' for list of commands.
(dlv) b main.main
Breakpoint 1 set at 0x108e83f for main.main() ./main.go:5
(dlv) c
> main.main() ./main.go:5 (hits goroutine(1):1 total:1) (PC: 0x108e83f)
1: package main
2:
3: import "./help"
4:
=> 5: func main() {
6: help.Help()
7: }
(dlv) s
> main.main() ./main.go:6 (PC: 0x108e84b)
1: package main
2:
3: import "./help"
4:
5: func main() {
=> 6: help.Help()
7: }
(dlv) s
> _/Users/pturley/Workspace/Go/src/debug-problem/help.Help() ./help/help.go:5 (PC: 0x108e76f)
Warning: debugging optimized function
1: package help
2:
3: import "fmt"
4:
=> 5: func Help() {
6: fmt.Println("I'm helping")
7: }
Notice that main() isn't optimized (as expected), but Help() is optimized, and delve prints a warning about that. If, for example, Help() had local variables, it would be unlikely you could view their values.
I tried building again with a few more options:
go build -a -x -gcflags="-N -l" main.go > log 2>&1
The -a option ensures Go doesn't rely on any cached build artifacts. The -x option causes Go to print all commands before executing them.
Here's the command that built main.go (white space inserted to improve clarity):
/opt/local/lib/go/pkg/tool/darwin_amd64/compile
-buildid XMSzm8g7wNG80cfFP4Nw/XMSzm8g7wNG80cfFP4Nw
-D _/Users/pturley/Workspace/Go/src/debug-problem
-importcfg $WORK/b001/importcfg
Here's the command that built help.go:
/opt/local/lib/go/pkg/tool/darwin_amd64/compile
-o $WORK/b002/_pkg_.a
-trimpath $WORK/b002
-p _/Users/pturley/Workspace/Go/src/debug-problem/help
-complete
-buildid Td3vdeSGgO-nwcrs810U/Td3vdeSGgO-nwcrs810U
-goversion go1.10
-D _/Users/pturley/Workspace/Go/src/debug-problem/help
-importcfg $WORK/b002/importcfg
-pack -c=4
./help.go
Note that the -N and -l options are missing in the latter command. If they had been propagated by go build (which I claim makes the most sense), all my code would be debuggable.