Skip to content

Commit 61c1e91

Browse files
authored
Fix //go/config:linkmode flag value not being effective (#3627)
The value of the flag was always overriden by the `linkmode` `go_binary` attribute, even if that attribute was at its default (`normal`) value. Instead, use a default of `auto` to distinguish this case from the case where no attribute value has been set explicitly. Fixes #3614 Closes #3615
1 parent 2626ff9 commit 61c1e91

File tree

5 files changed

+61
-3
lines changed

5 files changed

+61
-3
lines changed

docs/go/core/rules.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ This builds an executable from a set of source files,
165165
| <a id="go_binary-goos"></a>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 <code>--platforms</code>.<br><br> This disables cgo by default, since a cross-compiling C/C++ toolchain is rarely available. To force cgo, set <code>pure</code> = <code>off</code>.<br><br> See [Cross compilation] for more information. | String | optional | "auto" |
166166
| <a id="go_binary-gotags"></a>gotags | Enables a list of build tags when evaluating [build constraints]. Useful for conditional compilation. | List of strings | optional | [] |
167167
| <a id="go_binary-importpath"></a>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 | "" |
168-
| <a id="go_binary-linkmode"></a>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. <br><br> <ul> <li>`normal`: Builds a normal executable with position-dependent code.</li> <li>`pie`: Builds a position-independent executable.</li> <li>`plugin`: Builds a shared library that can be loaded as a Go plugin. Only supported on platforms that support plugins.</li> <li>`c-shared`: Builds a shared library that can be linked into a C program.</li> <li>`c-archive`: Builds an archive that can be linked into a C program.</li> </ul> | String | optional | "normal" |
168+
| <a id="go_binary-linkmode"></a>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. <br><br> <ul> <li>`auto` (default): Controlled by `//go/config:linkmode`, which defaults to `normal`.</li> <li>`normal`: Builds a normal executable with position-dependent code.</li> <li>`pie`: Builds a position-independent executable.</li> <li>`plugin`: Builds a shared library that can be loaded as a Go plugin. Only supported on platforms that support plugins.</li> <li>`c-shared`: Builds a shared library that can be linked into a C program.</li> <li>`c-archive`: Builds an archive that can be linked into a C program.</li> </ul> | String | optional | "auto" |
169169
| <a id="go_binary-msan"></a>msan | Controls whether code is instrumented for memory sanitization. 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:msan</code>. See [mode attributes], specifically [msan]. | String | optional | "auto" |
170170
| <a id="go_binary-out"></a>out | Sets the output filename for the generated executable. When set, <code>go_binary</code> 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 | "" |
171171
| <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" |

go/private/rules/binary.bzl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ load(
3737
)
3838
load(
3939
"//go/private:mode.bzl",
40+
"LINKMODES",
4041
"LINKMODES_EXECUTABLE",
4142
"LINKMODE_C_ARCHIVE",
4243
"LINKMODE_C_SHARED",
43-
"LINKMODE_NORMAL",
4444
"LINKMODE_PLUGIN",
4545
"LINKMODE_SHARED",
4646
)
@@ -385,11 +385,13 @@ _go_binary_kwargs = {
385385
""",
386386
),
387387
"linkmode": attr.string(
388-
default = LINKMODE_NORMAL,
388+
default = "auto",
389+
values = ["auto"] + LINKMODES,
389390
doc = """Determines how the binary should be built and linked. This accepts some of
390391
the same values as `go build -buildmode` and works the same way.
391392
<br><br>
392393
<ul>
394+
<li>`auto` (default): Controlled by `//go/config:linkmode`, which defaults to `normal`.</li>
393395
<li>`normal`: Builds a normal executable with position-dependent code.</li>
394396
<li>`pie`: Builds a position-independent executable.</li>
395397
<li>`plugin`: Builds a shared library that can be loaded as a Go plugin. Only supported on platforms that support plugins.</li>

tests/core/go_binary/BUILD.bazel

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
22
load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
33
load(":many_deps.bzl", "many_deps")
4+
load(":linkmode.bzl", "linkmode_pie_wrapper")
45

56
test_suite(name = "go_binary")
67

@@ -101,6 +102,12 @@ go_binary(
101102
tags = ["manual"],
102103
)
103104

105+
linkmode_pie_wrapper(
106+
name = "hello_pie_setting_bin",
107+
tags = ["manual"],
108+
target = ":hello_nopie_bin",
109+
)
110+
104111
go_test(
105112
name = "pie_test",
106113
srcs = [
@@ -112,10 +119,12 @@ go_test(
112119
"@io_bazel_rules_go//go/platform:darwin": [
113120
":hello_nopie_bin",
114121
":hello_pie_bin",
122+
":hello_pie_setting_bin",
115123
],
116124
"@io_bazel_rules_go//go/platform:linux": [
117125
":hello_nopie_bin",
118126
":hello_pie_bin",
127+
":hello_pie_setting_bin",
119128
],
120129
"//conditions:default": [],
121130
}),

tests/core/go_binary/linkmode.bzl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
_LINKMODE_SETTING = "//go/config:linkmode"
2+
3+
def _linkmode_pie_transition_impl(settings, attr):
4+
return {
5+
_LINKMODE_SETTING: "pie",
6+
}
7+
8+
_linkmode_pie_transition = transition(
9+
implementation = _linkmode_pie_transition_impl,
10+
inputs = [_LINKMODE_SETTING],
11+
outputs = [_LINKMODE_SETTING],
12+
)
13+
14+
def _linkmode_pie_wrapper(ctx):
15+
in_binary = ctx.attr.target[0][DefaultInfo].files.to_list()[0]
16+
out_binary = ctx.actions.declare_file(ctx.attr.name)
17+
ctx.actions.symlink(output = out_binary, target_file = in_binary)
18+
return [
19+
DefaultInfo(
20+
files = depset([out_binary]),
21+
),
22+
]
23+
24+
linkmode_pie_wrapper = rule(
25+
implementation = _linkmode_pie_wrapper,
26+
doc = """Provides the (only) file produced by target, but after transitioning the linkmode setting to PIE.""",
27+
attrs = {
28+
"target": attr.label(
29+
cfg = _linkmode_pie_transition,
30+
),
31+
"_allowlist_function_transition": attr.label(
32+
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
33+
),
34+
},
35+
)

tests/core/go_binary/pie_linux_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ func openELF(dir, bin string) (*elf.File, error) {
2323
return elf.NewFile(f)
2424
}
2525

26+
func TestPIESetting(t *testing.T) {
27+
e, err := openELF("tests/core/go_binary", "hello_pie_setting_bin")
28+
if err != nil {
29+
t.Fatal(err)
30+
}
31+
32+
// PIE binaries are implemented as shared libraries.
33+
if e.Type != elf.ET_DYN {
34+
t.Error("ELF binary is not position-independent.")
35+
}
36+
}
37+
2638
func TestPIE(t *testing.T) {
2739
e, err := openELF("tests/core/go_binary", "hello_pie_bin")
2840
if err != nil {

0 commit comments

Comments
 (0)