Skip to content

Commit

Permalink
Don't include non-executable go_binary in dependent's runfiles
Browse files Browse the repository at this point in the history
If a go_binary is built with a non-executable link mode such as
`c-archive`, its dependents currently pick up a runfile dependency on it
since its DefaultInfo specifies the resulting archive as an executable.
This is unnecessary as the dependent should be able to decide whether to
include the file (e.g. dynamic linking) or not (e.g. static linking).

With this commit, the executable field of the DefaultInfo is only
populated if the go_binary is built with an executable link mode.

Follow-up to bazel-contrib#3143
  • Loading branch information
fmeum committed May 12, 2022
1 parent 498d6ce commit 732425e
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 6 deletions.
27 changes: 22 additions & 5 deletions go/private/rules/binary.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ load(
)
load(
"//go/private:mode.bzl",
"LINKMODES_EXECUTABLE",
"LINKMODE_C_ARCHIVE",
"LINKMODE_C_SHARED",
"LINKMODE_NORMAL",
Expand Down Expand Up @@ -124,19 +125,35 @@ def _go_binary_impl(ctx):
executable = executable,
)

if go.mode.link in LINKMODES_EXECUTABLE:
# The executable is automatically added to the runfiles.
default_info = DefaultInfo(
files = depset([executable]),
runfiles = runfiles,
executable = executable,
)
else:
# Workaround for https://github.com/bazelbuild/bazel/issues/15043
# As of Bazel 5.1.1, native rules do not pick up the "files" of a data
# dependency's DefaultInfo, only the "data_runfiles". Since transitive
# non-data dependents should not pick up the executable as a runfile
# implicitly, the deprecated "default_runfiles" and "data_runfiles"
# constructor parameters have to be used.
default_info = DefaultInfo(
files = depset([executable]),
default_runfiles = runfiles,
data_runfiles = runfiles.merge(ctx.runfiles([executable])),
)

providers = [
library,
source,
archive,
default_info,
OutputGroupInfo(
cgo_exports = archive.cgo_exports,
compilation_outputs = [archive.data.file],
),
DefaultInfo(
files = depset([executable]),
runfiles = runfiles,
executable = executable,
),
]

# If the binary's linkmode is c-archive or c-shared, expose CcInfo
Expand Down
38 changes: 37 additions & 1 deletion tests/core/go_binary/non_executable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,51 @@ func TestMain(m *testing.M) {
Main: `
-- src/BUILD.bazel --
load("@io_bazel_rules_go//go:def.bzl", "go_binary")
load(":rules.bzl", "no_runfiles_check")
go_binary(
name = "archive",
srcs = ["archive.go"],
cgo = True,
linkmode = "c-archive",
)
cc_binary(
name = "main",
srcs = ["main.c"],
deps = [":archive"],
)
no_runfiles_check(
name = "no_runfiles",
target = ":main",
)
-- src/archive.go --
package main
import "C"
func main() {}
-- src/main.c --
int main() {}
-- src/rules.bzl --
def _no_runfiles_check_impl(ctx):
runfiles = ctx.attr.target[DefaultInfo].default_runfiles.files.to_list()
for runfile in runfiles:
if runfile.short_path not in ["src/main", "src/main.exe"]:
fail("Unexpected runfile: %s" % runfile.short_path)
no_runfiles_check = rule(
implementation = _no_runfiles_check_impl,
attrs = {
"target": attr.label(),
}
)
`,
})
}

func TestNonExecutableGoBinary(t *testing.T) {
func TestNonExecutableGoBinaryCantBeRun(t *testing.T) {
if err := bazel_testing.RunBazel("build", "//src:archive"); err != nil {
t.Fatal(err)
}
Expand All @@ -49,3 +79,9 @@ func TestNonExecutableGoBinary(t *testing.T) {
t.Errorf("Expected bazel run to fail due to //src:archive not being executable")
}
}

func TestNonExecutableGoBinaryNotInRunfiles(t *testing.T) {
if err := bazel_testing.RunBazel("build", "//src:no_runfiles"); err != nil {
t.Fatal(err)
}
}

0 comments on commit 732425e

Please sign in to comment.