diff --git a/docs/go/core/rules.md b/docs/go/core/rules.md index 5504bfb44..5fc72b8d2 100644 --- a/docs/go/core/rules.md +++ b/docs/go/core/rules.md @@ -126,7 +126,7 @@ Rules
go_binary(name, basename, cdeps, cgo, clinkopts, copts, cppopts, cxxopts, data, deps, embed, embedsrcs, env, gc_goopts, gc_linkopts, goarch, goos, gotags, importpath, linkmode, msan, - out, pgoprofile, pure, race, srcs, static, x_defs) + out, pgoprofile, pure, race, srcs, stamp, static, x_defs)This builds an executable from a set of source files, @@ -172,6 +172,7 @@ This builds an executable from a set of source files, | pure | Controls whether cgo source code and dependencies are compiled and linked, similar to setting
CGO_ENABLED
. May be one of on
, off
, or auto
. If auto
, pure mode is enabled when no C/C++ toolchain is configured or when cross-compiling. It's usually better to control this on the command line with --@io_bazel_rules_go//go/config:pure
. See [mode attributes], specifically [pure]. | String | optional | "auto" |
| race | Controls whether code is instrumented for race detection. May be one of on
, off
, or auto
. Not available when cgo is disabled. In most cases, it's better to control this on the command line with --@io_bazel_rules_go//go/config:race
. See [mode attributes], specifically [race]. | String | optional | "auto" |
| srcs | The list of Go source files that are compiled to create the package. Only .go
, .s
, and .syso
files are permitted, unless the cgo
attribute is set, in which case, .c .cc .cpp .cxx .h .hh .hpp .hxx .inc .m .mm
files are also permitted. Files may be filtered at build time using Go [build constraints]. | List of labels | optional | [] |
+| stamp | Whether to stamp this binary (0 for false, 1 for true). See [Defines and stamping] for more details on the behavior of stamping. If set to -1 (the default), stamping will be controlled by the --[no]stamp
flag. | Integer | optional | -1 |
| static | Controls whether a binary is statically linked. May be one of on
, off
, or auto
. Not available on all platforms or in all modes. It's usually better to control this on the command line with --@io_bazel_rules_go//go/config:static
. See [mode attributes], specifically [static]. | String | optional | "auto" |
| x_defs | Map of defines to add to the go link command. See [Defines and stamping] for examples of how to use these. | Dictionary: String -> String | optional | {} |
diff --git a/go/private/actions/archive.bzl b/go/private/actions/archive.bzl
index 023546f56..3c3f7b086 100644
--- a/go/private/actions/archive.bzl
+++ b/go/private/actions/archive.bzl
@@ -167,6 +167,7 @@ def emit_archive(go, source = None, _recompile_suffix = "", recompile_internal_d
_cover = as_tuple(source.cover),
_embedsrcs = as_tuple(source.embedsrcs),
_x_defs = tuple(source.x_defs.items()),
+ _stamp = source.stamp,
_gc_goopts = as_tuple(source.gc_goopts),
_cgo = source.cgo,
_cdeps = as_tuple(source.cdeps),
@@ -205,6 +206,7 @@ def emit_archive(go, source = None, _recompile_suffix = "", recompile_internal_d
libs = depset(direct = [out_lib], transitive = [a.libs for a in direct]),
transitive = depset([data], transitive = [a.transitive for a in direct]),
x_defs = x_defs,
+ stamp = source.stamp,
cgo_deps = depset(transitive = [cgo_deps] + [a.cgo_deps for a in direct]),
cgo_exports = cgo_exports,
runfiles = runfiles,
diff --git a/go/private/actions/link.bzl b/go/private/actions/link.bzl
index 6b0181463..96a2043ac 100644
--- a/go/private/actions/link.bzl
+++ b/go/private/actions/link.bzl
@@ -155,9 +155,11 @@ def emit_link(
# Process x_defs, and record whether stamping is used.
stamp_x_defs_volatile = False
stamp_x_defs_stable = False
+ should_stamp = go.stamp if (archive.stamp == -1) else bool(archive.stamp)
+
for k, v in archive.x_defs.items():
builder_args.add("-X", "%s=%s" % (k, v))
- if go.stamp:
+ if should_stamp:
stable_vars_count = (count_group_matches(v, "{STABLE_", "}") +
v.count("{BUILD_EMBED_LABEL}") +
v.count("{BUILD_USER}") +
diff --git a/go/private/context.bzl b/go/private/context.bzl
index b318908f3..8e044789a 100644
--- a/go/private/context.bzl
+++ b/go/private/context.bzl
@@ -281,6 +281,7 @@ def _library_to_source(go, attr, library, coverage_instrumented):
"cover": [],
"embedsrcs": embedsrcs,
"x_defs": {},
+ "stamp": getattr(attr, "stamp", -1),
"deps": deps,
"gc_goopts": _expand_opts(go, "gc_goopts", getattr(attr, "gc_goopts", [])),
"runfiles": _collect_runfiles(go, getattr(attr, "data", []), getattr(attr, "deps", [])),
diff --git a/go/private/rules/binary.bzl b/go/private/rules/binary.bzl
index 40a17f4d5..5735fad4a 100644
--- a/go/private/rules/binary.bzl
+++ b/go/private/rules/binary.bzl
@@ -264,6 +264,16 @@ _go_binary_kwargs = {
See [Defines and stamping] for examples of how to use these.
""",
),
+ "stamp": attr.int(
+ doc = """Whether to stamp this binary (0 for false, 1 for true).
+ See [Defines and stamping] for more details on the behavior of stamping.
+ If set to -1 (the default), stamping will be controlled by the `--[no]stamp` flag.
+ """,
+ default = -1,
+ # Optional bool would be nicer, but isn't supported:
+ # https://github.com/bazelbuild/bazel/issues/14434
+ values = [-1, 0, 1],
+ ),
"basename": attr.string(
doc = """The basename of this binary. The binary
basename may also be platform-dependent: on Windows, we add an .exe extension.
diff --git a/go/private/rules/test.bzl b/go/private/rules/test.bzl
index ecd37f078..3a5bfad1e 100644
--- a/go/private/rules/test.bzl
+++ b/go/private/rules/test.bzl
@@ -677,6 +677,7 @@ def _recompile_external_deps(go, external_source, internal_archive, library_labe
cover = arc_data._cover,
embedsrcs = as_list(arc_data._embedsrcs),
x_defs = dict(arc_data._x_defs),
+ stamp = arc_data._stamp,
deps = deps,
gc_goopts = as_list(arc_data._gc_goopts),
runfiles = go._ctx.runfiles(files = arc_data.data_files),
diff --git a/tests/core/go_binary/BUILD.bazel b/tests/core/go_binary/BUILD.bazel
index a5c1628e6..3e7b84ce8 100644
--- a/tests/core/go_binary/BUILD.bazel
+++ b/tests/core/go_binary/BUILD.bazel
@@ -53,7 +53,10 @@ many_deps(name = "many_deps")
go_test(
name = "stamp_test",
srcs = ["stamp_test.go"],
- data = [":stamp_bin"],
+ data = [
+ ":nostamp_bin",
+ ":stamp_bin",
+ ],
rundir = ".",
deps = ["@io_bazel_rules_go//go/tools/bazel:go_default_library"],
)
@@ -62,9 +65,24 @@ go_binary(
name = "stamp_bin",
srcs = ["stamp_bin.go"],
embed = [":stamp_embed"],
+ stamp = 1,
+ x_defs = {
+ "Bin": "Bin",
+ "example.com/stamp_dep.DepBin": "DepBin",
+ "BuildTime": "{BUILD_TIMESTAMP}",
+ },
+ deps = [":stamp_dep"],
+)
+
+go_binary(
+ name = "nostamp_bin",
+ srcs = ["stamp_bin.go"],
+ embed = [":stamp_embed"],
+ stamp = 0,
x_defs = {
"Bin": "Bin",
"example.com/stamp_dep.DepBin": "DepBin",
+ "BuildTime": "{BUILD_TIMESTAMP}",
},
deps = [":stamp_dep"],
)
diff --git a/tests/core/go_binary/stamp_bin.go b/tests/core/go_binary/stamp_bin.go
index e227be4c6..ada5157c2 100644
--- a/tests/core/go_binary/stamp_bin.go
+++ b/tests/core/go_binary/stamp_bin.go
@@ -6,11 +6,16 @@ import (
"example.com/stamp_dep"
)
-var Bin = "redacted"
+var (
+ Bin = "redacted"
+ BuildTime = "redacted"
+)
func main() {
fmt.Printf("Bin=%s\n", Bin)
fmt.Printf("Embed=%s\n", Embed)
fmt.Printf("DepSelf=%s\n", stamp_dep.DepSelf)
fmt.Printf("DepBin=%s\n", stamp_dep.DepBin)
+
+ fmt.Printf("BuildTime=%s\n", BuildTime)
}
diff --git a/tests/core/go_binary/stamp_test.go b/tests/core/go_binary/stamp_test.go
index 506cce5c0..720f315f0 100644
--- a/tests/core/go_binary/stamp_test.go
+++ b/tests/core/go_binary/stamp_test.go
@@ -2,6 +2,7 @@ package main
import (
"os/exec"
+ "regexp"
"strings"
"testing"
@@ -19,11 +20,30 @@ func TestStamp(t *testing.T) {
}
got := strings.TrimSpace(string(out))
- want := `Bin=Bin
+ want := regexp.MustCompile(`Bin=Bin
Embed=Embed
DepSelf=DepSelf
-DepBin=DepBin`
- if got != want {
+DepBin=DepBin
+BuildTime=[0-9]+`)
+
+ if !want.MatchString(got) {
+ t.Errorf("got:\n%s\nwant:\n%s", got, want)
+ }
+}
+
+func TestNoStamp(t *testing.T) {
+ bin, ok := bazel.FindBinary("tests/core/go_binary", "nostamp_bin")
+ if !ok {
+ t.Error("could not find stamp_bin")
+ }
+ out, err := exec.Command(bin).Output()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got := strings.TrimSpace(string(out))
+ want := "BuildTime=redacted"
+ if !strings.Contains(got, want) {
t.Errorf("got:\n%s\nwant:\n%s", got, want)
}
}