]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: rewrite paths for overlaid files using -trimpath
authorMichael Matloob <matloob@golang.org>
Wed, 14 Oct 2020 20:21:39 +0000 (16:21 -0400)
committerMichael Matloob <matloob@golang.org>
Thu, 15 Oct 2020 21:40:46 +0000 (21:40 +0000)
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>
src/cmd/go/internal/work/exec.go
src/cmd/go/internal/work/gc.go
src/cmd/go/internal/work/gccgo.go
src/cmd/go/testdata/script/build_overlay.txt
src/cmd/go/testdata/script/build_trimpath.txt

index 074bcc16c0a6767ea43163968b82c6201407ab3d..824a4b5a0a1b01d28f0c25a0d3a039bfc72d9b63 100644 (file)
@@ -2214,6 +2214,8 @@ func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []s
        // when -trimpath is enabled.
        if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") {
                if cfg.BuildTrimpath {
+                       // TODO(#39958): handle overlays
+
                        // Keep in sync with Action.trimpath.
                        // The trimmed paths are a little different, but we need to trim in the
                        // same situations.
index 1f15654c7911b6b4e8c2a21d93121c2a37634471..56ad1872be458e22d15144933a26ec9ea13c0eec 100644 (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.
                // Deleted files won't show up in when scanning directories earlier,
                // 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
                // doesn't exist on disk (this can happen when all the package's
                // 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)
        }
 
-       output, err = b.runOut(a, p.Dir, nil, args...)
+       output, err = b.runOut(a, base.Cwd, nil, args...)
        return ofile, output, err
 }
 
@@ -256,17 +254,28 @@ func (a *Action) trimpath() string {
        }
        rewrite := objdir + "=>"
 
-       // For "go build -trimpath", rewrite package source directory
-       // to a file system-independent path (just the import path).
+       rewriteDir := a.Package.Dir
        if cfg.BuildTrimpath {
                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 {
-                       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
 }
index dd5adf2d7b991670dcc2fb9b64f0b2e0531c7f24..ade8964b7c2e9df2ff986fe70b0e90c2ca21b265 100644 (file)
@@ -15,6 +15,7 @@ import (
 
        "cmd/go/internal/base"
        "cmd/go/internal/cfg"
+       "cmd/go/internal/fsys"
        "cmd/go/internal/load"
        "cmd/go/internal/str"
        "cmd/internal/pkgpath"
@@ -93,13 +94,37 @@ func (tools gccgoToolchain) gc(b *Builder, a *Action, archive string, importcfg
                        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+"=.")
-               args = append(args, "-ffile-prefix-map="+b.WorkDir+"=/tmp/go-build")
+
+       if b.gccSupportsFlag(args[:1], "-ffile-prefix-map=a=b") {
+               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...)
        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)
index 3b039901faf186a99691286ad53b8344cd5700e0..5f598f37e77a55288aa895e4cb644dd35374cc43 100644 (file)
@@ -9,36 +9,66 @@
 # file in an overlay and one file outside the overlay, which in turn imports m/dir,
 # which only has source files in the overlay.
 
+cd m
+
 ! go build .
 go build -overlay overlay.json -o main$GOEXE .
 exec ./main$goexe
 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)
 module m
 
 go 1.16
 
--- dir2/h.go --
+-- m/dir2/h.go --
 package dir2
 
 func PrintMessage() {
     printMessage()
 }
--- dir/foo.txt --
+-- m/dir/foo.txt --
 The build action code currently expects the package directory
 to exist, so it can run the compiler in that directory.
 TODO(matloob): Remove this requirement.
--- overlay.json --
+-- m/printpath/about.txt --
+the actual code is in the overlay
+-- m/overlay.json --
 {
     "Replace": {
         "f.go": "overlay/f.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
 
 import "m/dir2"
@@ -46,7 +76,7 @@ import "m/dir2"
 func main() {
     dir2.PrintMessage()
 }
--- overlay/dir_g.go --
+-- m/overlay/dir_g.go --
 package dir
 
 import "fmt"
@@ -54,7 +84,19 @@ import "fmt"
 func PrintMessage() {
     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
 
 import "m/dir"
index ad78bcf2b27718e54554ab00421c3462c474d72d..2c3bee8fdc7a925bb9bd9bdcee078a36b0ed9581 100644 (file)
@@ -9,6 +9,8 @@ env GO111MODULE=on
 mkdir $WORK/a/src/paths $WORK/b/src/paths
 cp paths.go $WORK/a/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/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
 
 
+# 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.
 # A binary built without -trimpath should contain GOPATH and GOROOT.
 env GO111MODULE=off
@@ -129,7 +154,8 @@ func check(data []byte, desc, dir string) {
        containsSlashDir := bytes.Contains(data, []byte(filepath.ToSlash(dir)))
        fmt.Printf("binary contains %s: %v\n", desc, containsDir || containsSlashDir)
 }
-
+-- overlay.json --
+{ "Replace": { "overlaydir/paths.go": "paths.go" } }
 -- go.mod --
 module paths