go: cmd/cgo: does not replace references to paths in GOROOT/ with $GOROOT
Normally Go compiles its own sources such that debug info pathnames look like $GOROOT/src/package/path.go
rather than /absolute/path/to/go/src/package/path.go
. However, this does not happen when compiling sources with cgo. In particular src/plugin/plugin_dlopen.go
produces this temporary file plugin_dlopen.cgo1.go
:
…
//line /tmp/nds-install-go_1_9/share/go/src/plugin/plugin_dlopen.go:43
func lastIndexByte(s string, c byte) int {
…
and after unpacking the resulting plugin.a
(ar x plugin.a
) and disassemly (go tool objdump _go_.o
) it can be seen that pure Go sources are refered through $GOROOT
, unlike cgo sources:
…
TEXT %22%22.Open(SB) gofile..$GOROOT/src/plugin/plugin.go
…
TEXT %22%22.lastIndexByte(SB) gofile../tmp/nds-install-go_1_9/share/go/src/plugin/plugin_dlopen.go
…
I would like the second line to be:
TEXT %22%22.lastIndexByte(SB) gofile..$GOROOT/src/plugin/plugin_dlopen.go
Here is a possible fix that replaces absolute path names in *.cgo1.go
:
diff --git a/src/go/printer/printer.go b/src/go/printer/printer.go
index dbb4bbd90c..16a0b84fa5 100644
--- a/src/go/printer/printer.go
+++ b/src/go/printer/printer.go
@@ -11,6 +11,7 @@ import (
"go/token"
"io"
"os"
+ "runtime"
"strconv"
"strings"
"text/tabwriter"
@@ -207,7 +208,8 @@ func (p *printer) lineFor(pos token.Pos) int {
func (p *printer) writeLineDirective(pos token.Position) {
if pos.IsValid() && (p.out.Line != pos.Line || p.out.Filename != pos.Filename) {
p.output = append(p.output, tabwriter.Escape) // protect '\n' in //line from tabwriter interpretation
- p.output = append(p.output, fmt.Sprintf("//line %s:%d\n", pos.Filename, pos.Line)...)
+ filename := strings.Replace(pos.Filename, runtime.GOROOT(), "$GOROOT", -1)
+ p.output = append(p.output, fmt.Sprintf("//line %s:%d\n", filename, pos.Line)...)
p.output = append(p.output, tabwriter.Escape)
// p.out must match the //line directive
p.out.Filename = pos.Filename
What version of Go are you using (go version
)?
go1.9
Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (go env
)?
NixOS Linux amd64
What did you do?
I tried to build journalbeat
that uses the plugin
package with Go 1.9. It failed Nix check that executables should not refer to Go root via an absolute pathname.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Comments: 18 (11 by maintainers)
Commits related to this issue
- build-go-package: temporarily disable buildDirCheck for go 1.9 — committed to triton/triton by codyopel 7 years ago
- [release-branch.go1.9] cmd/compile: replace GOROOT in //line directives The compiler replaces any path of the form /path/to/goroot/src/net/port.go with GOROOT/src/net/port.go so that the same object ... — committed to golang/go by crawshaw 7 years ago
Thanks @orivej that makes the problem in cmd/compile clear.
The Go binary distribution is built in /tmp/workdir/go. GOROOT_FINAL is set to /usr/local/go. This is the string that cmd/dist writes into cmd/internal/objabi/zbootstrap.go. This string, /usr/local/go is what AbsFile uses to replace the GOROOT with the string ‘$GOROOT’. But because the .a files we ship are built in /tmp/workdir/go, the string replace fails.
I believe the most robust fix is to have cmd/go pass its computed GOROOT to cmd/compile as an environment variable (if it’s not already set). That will mean cmd/compile does the right thing when the initial .a files are set, and also do the right thing when the entire GOROOT is moved later to an arbitrary directory.
That will resolve the release blocker part of this issue, though you may want to keep it around to look at changing the cmd/cgo program to not write absolute paths.