diff --git a/docs/go/core/rules.md b/docs/go/core/rules.md
index d30a47378d..52507673af 100644
--- a/docs/go/core/rules.md
+++ b/docs/go/core/rules.md
@@ -165,7 +165,7 @@ This builds an executable from a set of source files,
| goos | Forces a binary to be cross-compiled for a specific operating system. It's usually better to control this on the command line with --platforms
.
This disables cgo by default, since a cross-compiling C/C++ toolchain is rarely available. To force cgo, set pure
= off
.
See [Cross compilation] for more information. | String | optional | "auto" |
| gotags | Enables a list of build tags when evaluating [build constraints]. Useful for conditional compilation. | List of strings | optional | [] |
| importpath | The import path of this binary. Binaries can't actually be imported, but this may be used by [go_path] and other tools to report the location of source files. This may be inferred from embedded libraries. | String | optional | "" |
-| linkmode | Determines how the binary should be built and linked. This accepts some of the same values as `go build -buildmode` and works the same way.
- `normal`: Builds a normal executable with position-dependent code.
- `pie`: Builds a position-independent executable.
- `plugin`: Builds a shared library that can be loaded as a Go plugin. Only supported on platforms that support plugins.
- `c-shared`: Builds a shared library that can be linked into a C program.
- `c-archive`: Builds an archive that can be linked into a C program.
| String | optional | "normal" |
+| linkmode | Determines how the binary should be built and linked. This accepts some of the same values as `go build -buildmode` and works the same way.
- `auto` (default): Controlled by `//go/config:linkmode`, which defaults to `normal`.
- `normal`: Builds a normal executable with position-dependent code.
- `pie`: Builds a position-independent executable.
- `plugin`: Builds a shared library that can be loaded as a Go plugin. Only supported on platforms that support plugins.
- `c-shared`: Builds a shared library that can be linked into a C program.
- `c-archive`: Builds an archive that can be linked into a C program.
| String | optional | "auto" |
| msan | Controls whether code is instrumented for memory sanitization. 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:msan
. See [mode attributes], specifically [msan]. | String | optional | "auto" |
| out | Sets the output filename for the generated executable. When set, go_binary
will write this file without mode-specific directory prefixes, without linkmode-specific prefixes like "lib", and without platform-specific suffixes like ".exe". Note that without a mode-specific directory prefix, the output file (but not its dependencies) will be invalidated in Bazel's cache when changing configurations. | String | optional | "" |
| 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" |
diff --git a/go/private/rules/binary.bzl b/go/private/rules/binary.bzl
index 51530b04ca..690eb14a5e 100644
--- a/go/private/rules/binary.bzl
+++ b/go/private/rules/binary.bzl
@@ -37,10 +37,10 @@ load(
)
load(
"//go/private:mode.bzl",
+ "LINKMODES",
"LINKMODES_EXECUTABLE",
"LINKMODE_C_ARCHIVE",
"LINKMODE_C_SHARED",
- "LINKMODE_NORMAL",
"LINKMODE_PLUGIN",
"LINKMODE_SHARED",
)
@@ -385,11 +385,13 @@ _go_binary_kwargs = {
""",
),
"linkmode": attr.string(
- default = LINKMODE_NORMAL,
+ default = "auto",
+ values = ["auto"] + LINKMODES,
doc = """Determines how the binary should be built and linked. This accepts some of
the same values as `go build -buildmode` and works the same way.
+ - `auto` (default): Controlled by `//go/config:linkmode`, which defaults to `normal`.
- `normal`: Builds a normal executable with position-dependent code.
- `pie`: Builds a position-independent executable.
- `plugin`: Builds a shared library that can be loaded as a Go plugin. Only supported on platforms that support plugins.
diff --git a/tests/core/go_binary/BUILD.bazel b/tests/core/go_binary/BUILD.bazel
index 99a2d78492..89c211b7ac 100644
--- a/tests/core/go_binary/BUILD.bazel
+++ b/tests/core/go_binary/BUILD.bazel
@@ -1,6 +1,7 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
load(":many_deps.bzl", "many_deps")
+load(":linkmode.bzl", "linkmode_pie_wrapper")
test_suite(name = "go_binary")
@@ -101,6 +102,12 @@ go_binary(
tags = ["manual"],
)
+linkmode_pie_wrapper(
+ name = "hello_pie_setting_bin",
+ tags = ["manual"],
+ target = ":hello_nopie_bin",
+)
+
go_test(
name = "pie_test",
srcs = [
@@ -112,10 +119,12 @@ go_test(
"@io_bazel_rules_go//go/platform:darwin": [
":hello_nopie_bin",
":hello_pie_bin",
+ ":hello_pie_setting_bin",
],
"@io_bazel_rules_go//go/platform:linux": [
":hello_nopie_bin",
":hello_pie_bin",
+ ":hello_pie_setting_bin",
],
"//conditions:default": [],
}),
diff --git a/tests/core/go_binary/linkmode.bzl b/tests/core/go_binary/linkmode.bzl
new file mode 100644
index 0000000000..5dfb353020
--- /dev/null
+++ b/tests/core/go_binary/linkmode.bzl
@@ -0,0 +1,35 @@
+_LINKMODE_SETTING = "//go/config:linkmode"
+
+def _linkmode_pie_transition_impl(settings, attr):
+ return {
+ _LINKMODE_SETTING: "pie",
+ }
+
+_linkmode_pie_transition = transition(
+ implementation = _linkmode_pie_transition_impl,
+ inputs = [_LINKMODE_SETTING],
+ outputs = [_LINKMODE_SETTING],
+)
+
+def _linkmode_pie_wrapper(ctx):
+ in_binary = ctx.attr.target[0][DefaultInfo].files.to_list()[0]
+ out_binary = ctx.actions.declare_file(ctx.attr.name)
+ ctx.actions.symlink(output = out_binary, target_file = in_binary)
+ return [
+ DefaultInfo(
+ files = depset([out_binary]),
+ ),
+ ]
+
+linkmode_pie_wrapper = rule(
+ implementation = _linkmode_pie_wrapper,
+ doc = """Provides the (only) file produced by target, but after transitioning the linkmode setting to PIE.""",
+ attrs = {
+ "target": attr.label(
+ cfg = _linkmode_pie_transition,
+ ),
+ "_allowlist_function_transition": attr.label(
+ default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
+ ),
+ },
+)
diff --git a/tests/core/go_binary/pie_linux_test.go b/tests/core/go_binary/pie_linux_test.go
index 8b13550060..9248575c21 100644
--- a/tests/core/go_binary/pie_linux_test.go
+++ b/tests/core/go_binary/pie_linux_test.go
@@ -23,6 +23,18 @@ func openELF(dir, bin string) (*elf.File, error) {
return elf.NewFile(f)
}
+func TestPIESetting(t *testing.T) {
+ e, err := openELF("tests/core/go_binary", "hello_pie_setting_bin")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // PIE binaries are implemented as shared libraries.
+ if e.Type != elf.ET_DYN {
+ t.Error("ELF binary is not position-independent.")
+ }
+}
+
func TestPIE(t *testing.T) {
e, err := openELF("tests/core/go_binary", "hello_pie_bin")
if err != nil {