1
0
mirror of https://github.com/golang/go synced 2024-11-08 13:56:21 -07:00

cmd/go: rewrite paths for overlaid files using -trimpath

Pass the trimpath flag to cmd/compile to use the correct file paths
for files that are overlaid: that is, the "destination" path in the
overlay's Replace mapping rather than the "source" path.

Also fix paths to go source files provided to the gccgo compiler.

For #39958

Change-Id: I3741aeb2272bd0d5aa32cb28133b61e58264fd39
Reviewed-on: https://go-review.googlesource.com/c/go/+/257198
Trust: Michael Matloob <matloob@golang.org>
Trust: Bryan C. Mills <bcmills@google.com>
Run-TryBot: Michael Matloob <matloob@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
This commit is contained in:
Michael Matloob 2020-10-14 16:21:39 -04:00
parent 748c0d87e2
commit 21e441c461
5 changed files with 125 additions and 21 deletions

View File

@ -2214,6 +2214,8 @@ func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []s
// when -trimpath is enabled. // when -trimpath is enabled.
if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") { if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") {
if cfg.BuildTrimpath { if cfg.BuildTrimpath {
// TODO(#39958): handle overlays
// Keep in sync with Action.trimpath. // Keep in sync with Action.trimpath.
// The trimmed paths are a little different, but we need to trim in the // The trimmed paths are a little different, but we need to trim in the
// same situations. // same situations.

View File

@ -152,8 +152,6 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, s
// so these paths can be handed directly to tools. // so these paths can be handed directly to tools.
// Deleted files won't show up in when scanning directories earlier, // Deleted files won't show up in when scanning directories earlier,
// so OverlayPath will never return "" (meaning a deleted file) here. // so OverlayPath will never return "" (meaning a deleted file) here.
// TODO(#39958): Handle -trimprefix and other cases where
// tools depend on the names of the files that are passed in.
// TODO(#39958): Handle cases where the package directory // TODO(#39958): Handle cases where the package directory
// doesn't exist on disk (this can happen when all the package's // doesn't exist on disk (this can happen when all the package's
// files are in an overlay): the code expects the package directory // files are in an overlay): the code expects the package directory
@ -167,7 +165,7 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, s
args = append(args, f) args = append(args, f)
} }
output, err = b.runOut(a, p.Dir, nil, args...) output, err = b.runOut(a, base.Cwd, nil, args...)
return ofile, output, err return ofile, output, err
} }
@ -256,17 +254,28 @@ func (a *Action) trimpath() string {
} }
rewrite := objdir + "=>" rewrite := objdir + "=>"
// For "go build -trimpath", rewrite package source directory rewriteDir := a.Package.Dir
// to a file system-independent path (just the import path).
if cfg.BuildTrimpath { if cfg.BuildTrimpath {
if m := a.Package.Module; m != nil && m.Version != "" { if m := a.Package.Module; m != nil && m.Version != "" {
rewrite += ";" + a.Package.Dir + "=>" + m.Path + "@" + m.Version + strings.TrimPrefix(a.Package.ImportPath, m.Path) rewriteDir = m.Path + "@" + m.Version + strings.TrimPrefix(a.Package.ImportPath, m.Path)
} else { } else {
rewrite += ";" + a.Package.Dir + "=>" + a.Package.ImportPath rewriteDir = a.Package.ImportPath
} }
rewrite += ";" + a.Package.Dir + "=>" + rewriteDir
} }
// TODO(#39958): Add rewrite rules for overlaid files. // Add rewrites for overlays. The 'from' and 'to' paths in overlays don't need to have
// same basename, so go from the overlay contents file path (passed to the compiler)
// to the path the disk path would be rewritten to.
if fsys.OverlayFile != "" {
for _, filename := range a.Package.AllFiles() {
overlayPath, ok := fsys.OverlayPath(filepath.Join(a.Package.Dir, filename))
if !ok {
continue
}
rewrite += ";" + overlayPath + "=>" + filepath.Join(rewriteDir, filename)
}
}
return rewrite return rewrite
} }

View File

@ -15,6 +15,7 @@ import (
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/fsys"
"cmd/go/internal/load" "cmd/go/internal/load"
"cmd/go/internal/str" "cmd/go/internal/str"
"cmd/internal/pkgpath" "cmd/internal/pkgpath"
@ -93,13 +94,37 @@ func (tools gccgoToolchain) gc(b *Builder, a *Action, archive string, importcfg
args = append(args, "-I", root) args = append(args, "-I", root)
} }
} }
if cfg.BuildTrimpath && b.gccSupportsFlag(args[:1], "-ffile-prefix-map=a=b") {
args = append(args, "-ffile-prefix-map="+base.Cwd+"=.") if b.gccSupportsFlag(args[:1], "-ffile-prefix-map=a=b") {
args = append(args, "-ffile-prefix-map="+b.WorkDir+"=/tmp/go-build") if cfg.BuildTrimpath {
args = append(args, "-ffile-prefix-map="+base.Cwd+"=.")
args = append(args, "-ffile-prefix-map="+b.WorkDir+"=/tmp/go-build")
}
if fsys.OverlayFile != "" {
for _, name := range gofiles {
absPath := mkAbs(p.Dir, name)
overlayPath, ok := fsys.OverlayPath(absPath)
if !ok {
continue
}
toPath := absPath
// gccgo only applies the last matching rule, so also handle the case where
// BuildTrimpath is true and the path is relative to base.Cwd.
if cfg.BuildTrimpath && str.HasFilePathPrefix(toPath, base.Cwd) {
toPath = "." + toPath[len(base.Cwd):]
}
args = append(args, "-ffile-prefix-map="+overlayPath+"="+toPath)
}
}
} }
args = append(args, a.Package.Internal.Gccgoflags...) args = append(args, a.Package.Internal.Gccgoflags...)
for _, f := range gofiles { for _, f := range gofiles {
args = append(args, mkAbs(p.Dir, f)) f := mkAbs(p.Dir, f)
// Overlay files if necessary.
// See comment on gctoolchain.gc about overlay TODOs
f, _ = fsys.OverlayPath(f)
args = append(args, f)
} }
output, err = b.runOut(a, p.Dir, nil, args) output, err = b.runOut(a, p.Dir, nil, args)

View File

@ -9,36 +9,66 @@
# file in an overlay and one file outside the overlay, which in turn imports m/dir, # file in an overlay and one file outside the overlay, which in turn imports m/dir,
# which only has source files in the overlay. # which only has source files in the overlay.
cd m
! go build . ! go build .
go build -overlay overlay.json -o main$GOEXE . go build -overlay overlay.json -o main$GOEXE .
exec ./main$goexe exec ./main$goexe
stdout '^hello$' stdout '^hello$'
-- go.mod -- go build -overlay overlay.json -o print_abspath$GOEXE ./printpath
exec ./print_abspath$GOEXE
stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]main.go
go build -overlay overlay.json -o print_trimpath$GOEXE -trimpath ./printpath
exec ./print_trimpath$GOEXE
stdout ^m[/\\]printpath[/\\]main.go
# Run same tests but with gccgo.
env GO111MODULE=off
[!exec:gccgo] stop
! go build -compiler=gccgo .
go build -compiler=gccgo -overlay overlay.json -o main_gccgo$GOEXE .
exec ./main_gccgo$goexe
stdout '^hello$'
go build -compiler=gccgo -overlay overlay.json -o print_abspath_gccgo$GOEXE ./printpath
exec ./print_abspath_gccgo$GOEXE
stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]main.go
go build -compiler=gccgo -overlay overlay.json -o print_trimpath_gccgo$GOEXE -trimpath ./printpath
exec ./print_trimpath_gccgo$GOEXE
stdout ^\.[/\\]printpath[/\\]main.go
-- m/go.mod --
// TODO(matloob): how do overlays work with go.mod (especially if mod=readonly) // TODO(matloob): how do overlays work with go.mod (especially if mod=readonly)
module m module m
go 1.16 go 1.16
-- dir2/h.go -- -- m/dir2/h.go --
package dir2 package dir2
func PrintMessage() { func PrintMessage() {
printMessage() printMessage()
} }
-- dir/foo.txt -- -- m/dir/foo.txt --
The build action code currently expects the package directory The build action code currently expects the package directory
to exist, so it can run the compiler in that directory. to exist, so it can run the compiler in that directory.
TODO(matloob): Remove this requirement. TODO(matloob): Remove this requirement.
-- overlay.json -- -- m/printpath/about.txt --
the actual code is in the overlay
-- m/overlay.json --
{ {
"Replace": { "Replace": {
"f.go": "overlay/f.go", "f.go": "overlay/f.go",
"dir/g.go": "overlay/dir_g.go", "dir/g.go": "overlay/dir_g.go",
"dir2/i.go": "overlay/dir2_i.go" "dir2/i.go": "overlay/dir2_i.go",
"printpath/main.go": "overlay/printpath.go"
} }
} }
-- overlay/f.go -- -- m/overlay/f.go --
package main package main
import "m/dir2" import "m/dir2"
@ -46,7 +76,7 @@ import "m/dir2"
func main() { func main() {
dir2.PrintMessage() dir2.PrintMessage()
} }
-- overlay/dir_g.go -- -- m/overlay/dir_g.go --
package dir package dir
import "fmt" import "fmt"
@ -54,7 +84,19 @@ import "fmt"
func PrintMessage() { func PrintMessage() {
fmt.Println("hello") fmt.Println("hello")
} }
-- overlay/dir2_i.go -- -- m/overlay/printpath.go --
package main
import (
"fmt"
"runtime"
)
func main() {
_, file, _, _ := runtime.Caller(0)
fmt.Println(file)
}
-- m/overlay/dir2_i.go --
package dir2 package dir2
import "m/dir" import "m/dir"

View File

@ -9,6 +9,8 @@ env GO111MODULE=on
mkdir $WORK/a/src/paths $WORK/b/src/paths mkdir $WORK/a/src/paths $WORK/b/src/paths
cp paths.go $WORK/a/src/paths cp paths.go $WORK/a/src/paths
cp paths.go $WORK/b/src/paths cp paths.go $WORK/b/src/paths
cp overlay.json $WORK/a/src/paths
cp overlay.json $WORK/b/src/paths
cp go.mod $WORK/a/src/paths/ cp go.mod $WORK/a/src/paths/
cp go.mod $WORK/b/src/paths/ cp go.mod $WORK/b/src/paths/
@ -43,6 +45,29 @@ go build -trimpath -o $WORK/paths-b.exe
cmp -q $WORK/paths-a.exe $WORK/paths-b.exe cmp -q $WORK/paths-a.exe $WORK/paths-b.exe
# Same sequence of tests but with overlays.
# A binary built without -trimpath should contain the module root dir
# and GOROOT for debugging and stack traces.
cd $WORK/a/src/paths
go build -overlay overlay.json -o $WORK/paths-dbg.exe ./overlaydir
exec $WORK/paths-dbg.exe $WORK/paths-dbg.exe
stdout 'binary contains module root: true'
stdout 'binary contains GOROOT: true'
# A binary built with -trimpath should not contain the current workspace
# or GOROOT.
go build -overlay overlay.json -trimpath -o $WORK/paths-a.exe ./overlaydir
exec $WORK/paths-a.exe $WORK/paths-a.exe
stdout 'binary contains module root: false'
stdout 'binary contains GOROOT: false'
# Two binaries built from identical packages in different directories
# should be identical.
cd $WORK/b/src/paths
go build -overlay overlay.json -trimpath -o $WORK/paths-b.exe ./overlaydir
cmp -q $WORK/paths-a.exe $WORK/paths-b.exe
# Same sequence of tests but in GOPATH mode. # Same sequence of tests but in GOPATH mode.
# A binary built without -trimpath should contain GOPATH and GOROOT. # A binary built without -trimpath should contain GOPATH and GOROOT.
env GO111MODULE=off env GO111MODULE=off
@ -129,7 +154,8 @@ func check(data []byte, desc, dir string) {
containsSlashDir := bytes.Contains(data, []byte(filepath.ToSlash(dir))) containsSlashDir := bytes.Contains(data, []byte(filepath.ToSlash(dir)))
fmt.Printf("binary contains %s: %v\n", desc, containsDir || containsSlashDir) fmt.Printf("binary contains %s: %v\n", desc, containsDir || containsSlashDir)
} }
-- overlay.json --
{ "Replace": { "overlaydir/paths.go": "paths.go" } }
-- go.mod -- -- go.mod --
module paths module paths