1
0
mirror of https://github.com/golang/go synced 2024-11-17 16:44:44 -07:00

cmd/go: add -trimpath build flag

"go build -trimpath" trims the recorded file paths in the
resulting packages and executables to avoid recording
the names of any local directories. Instead, the files appear
to be stored in directories named either "go/src/..." (for the
standard library) or named after the module or package
in which the files appear.

Fixes #16860.

Change-Id: I433afeeb1fdeea641286b21693fee5e0a66d607e
Reviewed-on: https://go-review.googlesource.com/c/go/+/173345
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
This commit is contained in:
Russ Cox 2019-04-22 23:55:27 -04:00
parent 8a20fde697
commit 74695644e0
8 changed files with 85 additions and 15 deletions

View File

@ -155,6 +155,12 @@
// a space-separated list of build tags to consider satisfied during the // a space-separated list of build tags to consider satisfied during the
// build. For more information about build tags, see the description of // build. For more information about build tags, see the description of
// build constraints in the documentation for the go/build package. // build constraints in the documentation for the go/build package.
// -trimpath
// remove all file system paths from the resulting executable.
// Instead of absolute file system paths, the recorded file names
// will begin with either "go" (for the standard library),
// or a module path@version (when using modules),
// or a plain import path (when using GOPATH).
// -toolexec 'cmd args' // -toolexec 'cmd args'
// a program to use to invoke toolchain programs like vet and asm. // a program to use to invoke toolchain programs like vet and asm.
// For example, instead of running asm, the go command will run // For example, instead of running asm, the go command will run

View File

@ -38,6 +38,7 @@ var (
BuildToolchainName string BuildToolchainName string
BuildToolchainCompiler func() string BuildToolchainCompiler func() string
BuildToolchainLinker func() string BuildToolchainLinker func() string
BuildTrimpath bool // -trimpath flag
BuildV bool // -v flag BuildV bool // -v flag
BuildWork bool // -work flag BuildWork bool // -work flag
BuildX bool // -x flag BuildX bool // -x flag

View File

@ -108,6 +108,12 @@ and test commands:
a space-separated list of build tags to consider satisfied during the a space-separated list of build tags to consider satisfied during the
build. For more information about build tags, see the description of build. For more information about build tags, see the description of
build constraints in the documentation for the go/build package. build constraints in the documentation for the go/build package.
-trimpath
remove all file system paths from the resulting executable.
Instead of absolute file system paths, the recorded file names
will begin with either "go" (for the standard library),
or a module path@version (when using modules),
or a plain import path (when using GOPATH).
-toolexec 'cmd args' -toolexec 'cmd args'
a program to use to invoke toolchain programs like vet and asm. a program to use to invoke toolchain programs like vet and asm.
For example, instead of running asm, the go command will run For example, instead of running asm, the go command will run
@ -229,6 +235,7 @@ func AddBuildFlags(cmd *base.Command) {
cmd.Flag.BoolVar(&cfg.BuildMSan, "msan", false, "") cmd.Flag.BoolVar(&cfg.BuildMSan, "msan", false, "")
cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildContext.BuildTags), "tags", "") cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildContext.BuildTags), "tags", "")
cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildToolexec), "toolexec", "") cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildToolexec), "toolexec", "")
cmd.Flag.BoolVar(&cfg.BuildTrimpath, "trimpath", false, "")
cmd.Flag.BoolVar(&cfg.BuildWork, "work", false, "") cmd.Flag.BoolVar(&cfg.BuildWork, "work", false, "")
// Undocumented, unstable debugging flags. // Undocumented, unstable debugging flags.

View File

@ -1930,7 +1930,8 @@ func joinUnambiguously(a []string) string {
q := strconv.Quote(s) q := strconv.Quote(s)
// A gccgo command line can contain -( and -). // A gccgo command line can contain -( and -).
// Make sure we quote them since they are special to the shell. // Make sure we quote them since they are special to the shell.
if s == "" || strings.ContainsAny(s, " ()") || len(q) > len(s)+2 { // The trimpath argument can also contain > (part of =>) and ;. Quote those too.
if s == "" || strings.ContainsAny(s, " ()>;") || len(q) > len(s)+2 {
buf.WriteString(q) buf.WriteString(q)
} else { } else {
buf.WriteString(s) buf.WriteString(s)

View File

@ -117,7 +117,7 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, s
} }
} }
args := []interface{}{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", trimDir(a.Objdir), gcflags, gcargs, "-D", p.Internal.LocalPrefix} args := []interface{}{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", a.trimpath(), gcflags, gcargs, "-D", p.Internal.LocalPrefix}
if importcfg != nil { if importcfg != nil {
if err := b.writeFile(objdir+"importcfg", importcfg); err != nil { if err := b.writeFile(objdir+"importcfg", importcfg); err != nil {
return "", nil, err return "", nil, err
@ -215,17 +215,33 @@ CheckFlags:
return c return c
} }
func trimDir(dir string) string { // trimpath returns the -trimpath argument to use
if len(dir) > 1 && dir[len(dir)-1] == filepath.Separator { // when compiling the action.
dir = dir[:len(dir)-1] func (a *Action) trimpath() string {
// Strip the object directory entirely.
objdir := a.Objdir
if len(objdir) > 1 && objdir[len(objdir)-1] == filepath.Separator {
objdir = objdir[:len(objdir)-1]
} }
return dir rewrite := objdir + "=>"
// For "go build -trimpath", rewrite package source directory
// to a file system-independent path (just the import path).
if cfg.BuildTrimpath {
if m := a.Package.Module; m != nil {
rewrite += ";" + m.Dir + "=>" + m.Path + "@" + m.Version
} else {
rewrite += ";" + a.Package.Dir + "=>" + a.Package.ImportPath
}
}
return rewrite
} }
func asmArgs(a *Action, p *load.Package) []interface{} { func asmArgs(a *Action, p *load.Package) []interface{} {
// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files. // Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
inc := filepath.Join(cfg.GOROOT, "pkg", "include") inc := filepath.Join(cfg.GOROOT, "pkg", "include")
args := []interface{}{cfg.BuildToolexec, base.Tool("asm"), "-trimpath", trimDir(a.Objdir), "-I", a.Objdir, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, forcedAsmflags, p.Internal.Asmflags} args := []interface{}{cfg.BuildToolexec, base.Tool("asm"), "-trimpath", a.trimpath(), "-I", a.Objdir, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, forcedAsmflags, p.Internal.Asmflags}
if p.ImportPath == "runtime" && cfg.Goarch == "386" { if p.ImportPath == "runtime" && cfg.Goarch == "386" {
for _, arg := range forcedAsmflags { for _, arg := range forcedAsmflags {
if arg == "-dynlink" { if arg == "-dynlink" {
@ -567,7 +583,11 @@ func (gcToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string)
dir, out = filepath.Split(out) dir, out = filepath.Split(out)
} }
return b.run(root, dir, root.Package.ImportPath, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, "-importcfg", importcfg, ldflags, mainpkg) env := []string{}
if cfg.BuildTrimpath {
env = append(env, "GOROOT_FINAL=go")
}
return b.run(root, dir, root.Package.ImportPath, env, cfg.BuildToolexec, base.Tool("link"), "-o", out, "-importcfg", importcfg, ldflags, mainpkg)
} }
func (gcToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error { func (gcToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error {

View File

@ -539,6 +539,13 @@ func (ts *testScript) cmdEnv(neg bool, args []string) {
if neg { if neg {
ts.fatalf("unsupported: ! env") ts.fatalf("unsupported: ! env")
} }
conv := func(s string) string { return s }
if len(args) > 0 && args[0] == "-r" {
conv = regexp.QuoteMeta
args = args[1:]
}
if len(args) == 0 { if len(args) == 0 {
printed := make(map[string]bool) // env list can have duplicates; only print effective value (from envMap) once printed := make(map[string]bool) // env list can have duplicates; only print effective value (from envMap) once
for _, kv := range ts.env { for _, kv := range ts.env {
@ -556,8 +563,9 @@ func (ts *testScript) cmdEnv(neg bool, args []string) {
fmt.Fprintf(&ts.log, "%s=%s\n", env, ts.envMap[env]) fmt.Fprintf(&ts.log, "%s=%s\n", env, ts.envMap[env])
continue continue
} }
ts.env = append(ts.env, env) key, val := env[:i], conv(env[i+1:])
ts.envMap[env[:i]] = env[i+1:] ts.env = append(ts.env, key+"="+val)
ts.envMap[key] = val
} }
} }
@ -743,6 +751,11 @@ func scriptMatch(ts *testScript, neg bool, args []string, text, name string) {
} }
args = args[1:] args = args[1:]
} }
quiet := false
if len(args) >= 1 && args[0] == "-q" {
quiet = true
args = args[1:]
}
extraUsage := "" extraUsage := ""
want := 1 want := 1
@ -773,14 +786,14 @@ func scriptMatch(ts *testScript, neg bool, args []string, text, name string) {
if neg { if neg {
if re.MatchString(text) { if re.MatchString(text) {
if isGrep { if isGrep && !quiet {
fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text) fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text)
} }
ts.fatalf("unexpected match for %#q found in %s: %s", pattern, name, re.FindString(text)) ts.fatalf("unexpected match for %#q found in %s: %s", pattern, name, re.FindString(text))
} }
} else { } else {
if !re.MatchString(text) { if !re.MatchString(text) {
if isGrep { if isGrep && !quiet {
fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text) fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text)
} }
ts.fatalf("no match for %#q found in %s", pattern, name) ts.fatalf("no match for %#q found in %s", pattern, name)
@ -788,7 +801,7 @@ func scriptMatch(ts *testScript, neg bool, args []string, text, name string) {
if n > 0 { if n > 0 {
count := len(re.FindAllString(text, -1)) count := len(re.FindAllString(text, -1))
if count != n { if count != n {
if isGrep { if isGrep && !quiet {
fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text) fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text)
} }
ts.fatalf("have %d matches for %#q, want %d", count, pattern, n) ts.fatalf("have %d matches for %#q, want %d", count, pattern, n)

View File

@ -111,9 +111,11 @@ The commands are:
src can include "stdout" or "stderr" to use the standard output or standard error src can include "stdout" or "stderr" to use the standard output or standard error
from the most recent exec or go command. from the most recent exec or go command.
- env [key=value...] - env [-r] [key=value...]
With no arguments, print the environment (useful for debugging). With no arguments, print the environment (useful for debugging).
Otherwise add the listed key=value pairs to the environment. Otherwise add the listed key=value pairs to the environment.
The -r flag causes the values to be escaped using regexp.QuoteMeta
before being recorded.
- [!] exec program [args...] [&] - [!] exec program [args...] [&]
Run the given executable program with the arguments. Run the given executable program with the arguments.
@ -135,9 +137,10 @@ The commands are:
Run the (test copy of the) go command with the given arguments. Run the (test copy of the) go command with the given arguments.
It must (or must not) succeed. It must (or must not) succeed.
- [!] grep [-count=N] pattern file - [!] grep [-count=N] [-q] pattern file
The file's content must (or must not) match the regular expression pattern. The file's content must (or must not) match the regular expression pattern.
For positive matches, -count=N specifies an exact number of matches to require. For positive matches, -count=N specifies an exact number of matches to require.
The -q flag disables printing the file content on a mismatch.
- mkdir path... - mkdir path...
Create the listed directories, if they do not already exists. Create the listed directories, if they do not already exists.

View File

@ -0,0 +1,19 @@
env -r GOROOT_REGEXP=$GOROOT
env -r WORK_REGEXP=$WORK
env GOROOT GOROOT_REGEXP WORK WORK_REGEXP
go build -trimpath -o hello.exe hello.go
! grep -q $GOROOT_REGEXP hello.exe
! grep -q $WORK_REGEXP hello.exe
env GO111MODULE=on
go build -trimpath -o fortune.exe rsc.io/fortune
! grep -q $GOROOT_REGEXP fortune.exe
! grep -q $WORK_REGEXP fortune.exe
-- hello.go --
package main
func main() { println("hello") }
-- go.mod --
module m