cmd/go: stamp tags and flags in build info

Toolchain flags (like -gcflags), build tags (including race and msan),
and cgo variables (including CGO_ENABLED, CGO_CPPFLAGS and others) are
now stamped into binaries.

For #37475

Change-Id: I9023e682c0618f91805434946c6bc937536b69bb
Reviewed-on: https://go-review.googlesource.com/c/go/+/355493
Trust: Jay Conrod <jayconrod@google.com>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
This commit is contained in:
Jay Conrod 2021-10-12 15:08:54 -07:00
parent a37bebc042
commit 0fd0639e4c
7 changed files with 115 additions and 8 deletions

View File

@ -131,6 +131,11 @@
//
// -asmflags '[pattern=]arg list'
// arguments to pass on each go tool asm invocation.
// -buildinfo
// Whether to stamp binaries with build flags. By default, the compiler name
// (gc or gccgo), toolchain flags (like -gcflags), and environment variables
// containing flags (like CGO_CFLAGS) are stamped into binaries. Use
// -buildinfo=false to omit build information. See also -buildvcs.
// -buildmode mode
// build mode to use. See 'go help buildmode' for more.
// -buildvcs
@ -138,7 +143,7 @@
// version control information is stamped into a binary if the main package
// and the main module containing it are in the repository containing the
// current directory (if there is a repository). Use -buildvcs=false to
// omit version control information.
// omit version control information. See also -buildinfo.
// -compiler name
// name of compiler to use, as in runtime.Compiler (gccgo or gc).
// -gccgoflags '[pattern=]arg list'

View File

@ -1380,7 +1380,7 @@ func TestLdFlagsLongArgumentsIssue42295(t *testing.T) {
for buf.Len() < sys.ExecArgLengthLimit+1 {
buf.WriteString(testStr)
}
tg.run("run", "-ldflags", fmt.Sprintf(`-X "main.extern=%s"`, buf.String()), tg.path("main.go"))
tg.run("run", "-buildinfo=false", "-ldflags", fmt.Sprintf(`-X "main.extern=%s"`, buf.String()), tg.path("main.go"))
if tg.stderr.String() != buf.String() {
t.Errorf("strings differ")
}

View File

@ -25,6 +25,7 @@ import (
// These are general "build flags" used by build and other commands.
var (
BuildA bool // -a flag
BuildBuildinfo bool // -buildinfo flag
BuildBuildmode string // -buildmode flag
BuildBuildvcs bool // -buildvcs flag
BuildContext = defaultContext()

View File

@ -22,6 +22,7 @@ var (
// that allows specifying different effective flags for different packages.
// See 'go help build' for more details about per-package flags.
type PerPackageFlag struct {
raw string
present bool
values []ppfValue
}
@ -39,6 +40,7 @@ func (f *PerPackageFlag) Set(v string) error {
// set is the implementation of Set, taking a cwd (current working directory) for easier testing.
func (f *PerPackageFlag) set(v, cwd string) error {
f.raw = v
f.present = true
match := func(p *Package) bool { return p.Internal.CmdlinePkg || p.Internal.CmdlineFiles } // default predicate with no pattern
// For backwards compatibility with earlier flag splitting, ignore spaces around flags.
@ -72,9 +74,7 @@ func (f *PerPackageFlag) set(v, cwd string) error {
return nil
}
// String is required to implement flag.Value.
// It is not used, because cmd/go never calls flag.PrintDefaults.
func (f *PerPackageFlag) String() string { return "<PerPackageFlag>" }
func (f *PerPackageFlag) String() string { return f.raw }
// Present reports whether the flag appeared on the command line.
func (f *PerPackageFlag) Present() bool {

View File

@ -2268,6 +2268,35 @@ func (p *Package) setBuildInfo() {
Main: main,
Deps: deps,
}
appendSetting := func(key, value string) {
info.Settings = append(info.Settings, debug.BuildSetting{Key: key, Value: value})
}
// Add command-line flags relevant to the build.
// This is informational, not an exhaustive list.
if cfg.BuildBuildinfo {
appendSetting("compiler", cfg.BuildContext.Compiler)
if BuildAsmflags.present {
appendSetting("asmflags", BuildAsmflags.String())
}
if BuildGcflags.present && cfg.BuildContext.Compiler == "gc" {
appendSetting("gcflags", BuildGcflags.String())
}
if BuildGccgoflags.present && cfg.BuildContext.Compiler == "gccgo" {
appendSetting("gccgoflags", BuildGccgoflags.String())
}
if BuildLdflags.present {
appendSetting("ldflags", BuildLdflags.String())
}
tags := append(cfg.BuildContext.BuildTags, cfg.BuildContext.ToolTags...)
appendSetting("tags", strings.Join(tags, ","))
appendSetting("CGO_ENABLED", strconv.FormatBool(cfg.BuildContext.CgoEnabled))
if cfg.BuildContext.CgoEnabled {
for _, name := range []string{"CGO_CPPFLAGS", "CGO_CFLAGS", "CGO_CXXFLAGS", "CGO_LDFLAGS"} {
appendSetting(name, cfg.Getenv(name))
}
}
}
// Add VCS status if all conditions are true:
//
@ -2328,10 +2357,10 @@ func (p *Package) setBuildInfo() {
setVCSError(err)
return
}
info.Settings = []debug.BuildSetting{
info.Settings = append(info.Settings, []debug.BuildSetting{
{Key: vcsCmd.Cmd + "revision", Value: st.Revision},
{Key: vcsCmd.Cmd + "uncommitted", Value: strconv.FormatBool(st.Uncommitted)},
}
}...)
}
text, err := info.MarshalText()

View File

@ -85,6 +85,11 @@ and test commands:
-asmflags '[pattern=]arg list'
arguments to pass on each go tool asm invocation.
-buildinfo
Whether to stamp binaries with build flags. By default, the compiler name
(gc or gccgo), toolchain flags (like -gcflags), and environment variables
containing flags (like CGO_CFLAGS) are stamped into binaries. Use
-buildinfo=false to omit build information. See also -buildvcs.
-buildmode mode
build mode to use. See 'go help buildmode' for more.
-buildvcs
@ -92,7 +97,7 @@ and test commands:
version control information is stamped into a binary if the main package
and the main module containing it are in the repository containing the
current directory (if there is a repository). Use -buildvcs=false to
omit version control information.
omit version control information. See also -buildinfo.
-compiler name
name of compiler to use, as in runtime.Compiler (gccgo or gc).
-gccgoflags '[pattern=]arg list'
@ -308,6 +313,7 @@ func AddBuildFlags(cmd *base.Command, mask BuildFlagMask) {
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.BuildBuildinfo, "buildinfo", true, "")
cmd.Flag.BoolVar(&cfg.BuildBuildvcs, "buildvcs", true, "")
// Undocumented, unstable debugging flags.

View File

@ -0,0 +1,66 @@
[short] skip
# Compiler name is always added.
go build
go version -m m$GOEXE
stdout '^\tbuild\tcompiler\tgc$'
! stdout asmflags|gcflags|ldflags|gccgoflags
# Toolchain flags are added if present.
# The raw flags are included, with package patterns if specified.
go build -asmflags=all=-spectre=all
go version -m m$GOEXE
stdout '^\tbuild\tasmflags\tall=-spectre=all$'
go build -gcflags=all=-spectre=all
go version -m m$GOEXE
stdout '^\tbuild\tgcflags\tall=-spectre=all$'
go build -ldflags=-w
go version -m m$GOEXE
stdout '^\tbuild\tldflags\t-w$'
# gccgoflags are not added when gc is used, and vice versa.
# TODO: test gccgo.
go build -gccgoflags=all=UNUSED
go version -m m$GOEXE
! stdout gccgoflags
# Build and tool tags are added but not release tags.
# "race" is included with build tags but not "cgo".
go build -tags=a,b
go version -m m$GOEXE
stdout '^\tbuild\ttags\ta,b(,goexperiment\.[a-z0-9]+)*$'
[race] go build -race
[race] go version -m m$GOEXE
[race] stdout '^\tbuild\ttags\t.*race.*$'
# CGO flags are separate settings.
# CGO_ENABLED is always present.
# Other flags are added if CGO_ENABLED is true.
env CGO_ENABLED=0
go build
go version -m m$GOEXE
stdout '^\tbuild\tCGO_ENABLED\tfalse$'
! stdout CGO_CPPFLAGS|CGO_CFLAGS|CGO_CXXFLAGS|CGO_LDFLAGS
[cgo] env CGO_ENABLED=1
[cgo] env CGO_CPPFLAGS=-DFROM_CPPFLAGS=1
[cgo] env CGO_CFLAGS=-DFROM_CFLAGS=1
[cgo] env CGO_CXXFLAGS=-DFROM_CXXFLAGS=1
[cgo] env CGO_LDFLAGS=-L/extra/dir/does/not/exist
[cgo] go build
[cgo] go version -m m$GOEXE
[cgo] stdout '^\tbuild\tCGO_ENABLED\ttrue$'
[cgo] stdout '^\tbuild\tCGO_CPPFLAGS\t-DFROM_CPPFLAGS=1$'
[cgo] stdout '^\tbuild\tCGO_CFLAGS\t-DFROM_CFLAGS=1$'
[cgo] stdout '^\tbuild\tCGO_CXXFLAGS\t-DFROM_CXXFLAGS=1$'
[cgo] stdout '^\tbuild\tCGO_LDFLAGS\t-L/extra/dir/does/not/exist$'
-- go.mod --
module example.com/m
go 1.18
-- m.go --
package main
func main() {}