// 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.
// 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
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
}
}
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
}
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/fsys"
"cmd/go/internal/load"
"cmd/go/internal/str"
"cmd/internal/pkgpath"
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)
# 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"
func main() {
dir2.PrintMessage()
}
--- overlay/dir_g.go --
+-- m/overlay/dir_g.go --
package dir
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"
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/
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
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