Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stamping support to go_binary #3980

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/go/core/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ Rules
<pre>
go_binary(<a href="#go_binary-name">name</a>, <a href="#go_binary-basename">basename</a>, <a href="#go_binary-cdeps">cdeps</a>, <a href="#go_binary-cgo">cgo</a>, <a href="#go_binary-clinkopts">clinkopts</a>, <a href="#go_binary-copts">copts</a>, <a href="#go_binary-cppopts">cppopts</a>, <a href="#go_binary-cxxopts">cxxopts</a>, <a href="#go_binary-data">data</a>, <a href="#go_binary-deps">deps</a>, <a href="#go_binary-embed">embed</a>,
<a href="#go_binary-embedsrcs">embedsrcs</a>, <a href="#go_binary-env">env</a>, <a href="#go_binary-gc_goopts">gc_goopts</a>, <a href="#go_binary-gc_linkopts">gc_linkopts</a>, <a href="#go_binary-goarch">goarch</a>, <a href="#go_binary-goos">goos</a>, <a href="#go_binary-gotags">gotags</a>, <a href="#go_binary-importpath">importpath</a>, <a href="#go_binary-linkmode">linkmode</a>, <a href="#go_binary-msan">msan</a>,
<a href="#go_binary-out">out</a>, <a href="#go_binary-pgoprofile">pgoprofile</a>, <a href="#go_binary-pure">pure</a>, <a href="#go_binary-race">race</a>, <a href="#go_binary-srcs">srcs</a>, <a href="#go_binary-static">static</a>, <a href="#go_binary-x_defs">x_defs</a>)
<a href="#go_binary-out">out</a>, <a href="#go_binary-pgoprofile">pgoprofile</a>, <a href="#go_binary-pure">pure</a>, <a href="#go_binary-race">race</a>, <a href="#go_binary-srcs">srcs</a>, <a href="#go_binary-stamp">stamp</a>, <a href="#go_binary-static">static</a>, <a href="#go_binary-x_defs">x_defs</a>)
</pre>

This builds an executable from a set of source files,
Expand Down Expand Up @@ -172,6 +172,7 @@ This builds an executable from a set of source files,
| <a id="go_binary-pure"></a>pure | Controls whether cgo source code and dependencies are compiled and linked, similar to setting <code>CGO_ENABLED</code>. May be one of <code>on</code>, <code>off</code>, or <code>auto</code>. If <code>auto</code>, 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 <code>--@io_bazel_rules_go//go/config:pure</code>. See [mode attributes], specifically [pure]. | String | optional | "auto" |
| <a id="go_binary-race"></a>race | Controls whether code is instrumented for race detection. May be one of <code>on</code>, <code>off</code>, or <code>auto</code>. Not available when cgo is disabled. In most cases, it's better to control this on the command line with <code>--@io_bazel_rules_go//go/config:race</code>. See [mode attributes], specifically [race]. | String | optional | "auto" |
| <a id="go_binary-srcs"></a>srcs | The list of Go source files that are compiled to create the package. Only <code>.go</code>, <code>.s</code>, and <code>.syso</code> files are permitted, unless the <code>cgo</code> attribute is set, in which case, <code>.c .cc .cpp .cxx .h .hh .hpp .hxx .inc .m .mm</code> files are also permitted. Files may be filtered at build time using Go [build constraints]. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | [] |
| <a id="go_binary-stamp"></a>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 <code>--[no]stamp</code> flag. | Integer | optional | -1 |
| <a id="go_binary-static"></a>static | Controls whether a binary is statically linked. May be one of <code>on</code>, <code>off</code>, or <code>auto</code>. Not available on all platforms or in all modes. It's usually better to control this on the command line with <code>--@io_bazel_rules_go//go/config:static</code>. See [mode attributes], specifically [static]. | String | optional | "auto" |
| <a id="go_binary-x_defs"></a>x_defs | Map of defines to add to the go link command. See [Defines and stamping] for examples of how to use these. | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | {} |

Expand Down
2 changes: 2 additions & 0 deletions go/private/actions/archive.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion go/private/actions/link.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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}") +
Expand Down
1 change: 1 addition & 0 deletions go/private/context.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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", [])),
Expand Down
10 changes: 10 additions & 0 deletions go/private/rules/binary.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions go/private/rules/test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
20 changes: 19 additions & 1 deletion tests/core/go_binary/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
)
Expand All @@ -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"],
)
Expand Down
7 changes: 6 additions & 1 deletion tests/core/go_binary/stamp_bin.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
26 changes: 23 additions & 3 deletions tests/core/go_binary/stamp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"os/exec"
"regexp"
"strings"
"testing"

Expand All @@ -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)
}
}