diff --git a/go/core.rst b/go/core.rst index 55f5a24b99..b6396b7839 100644 --- a/go/core.rst +++ b/go/core.rst @@ -386,6 +386,15 @@ Attributes | Subject to `"Make variable"`_ substitution and `Bourne shell tokenization`_. | | Only valid if :param:`cgo` = :value:`True`. | +----------------------------+-----------------------------+---------------------------------------+ +| :param:`out` | :type:`string` | :value:`""` | ++----------------------------+-----------------------------+---------------------------------------+ +| 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. | ++----------------------------+-----------------------------+---------------------------------------+ go_test ~~~~~~~ diff --git a/go/private/actions/binary.bzl b/go/private/actions/binary.bzl index 89a764b76d..cfd6d63a60 100644 --- a/go/private/actions/binary.bzl +++ b/go/private/actions/binary.bzl @@ -23,24 +23,27 @@ load( ) def emit_binary(go, - name="", + name = "", source = None, gc_linkopts = [], - linkstamp=None, - version_file=None, - info_file=None): + linkstamp = None, + version_file = None, + info_file = None, + executable = None): """See go/toolchains.rst#binary for full documentation.""" - if name == "": fail("name is a required parameter") + if name == "" and executable == None: + fail("either name or executable must be set") archive = go.archive(go, source) - extension = go.exe_extension - if go.mode.link == LINKMODE_C_SHARED: - name = "lib" + name # shared libraries need a "lib" prefix in their name - extension = go.shared_extension - elif go.mode.link == LINKMODE_C_ARCHIVE: - extension = ARCHIVE_EXTENSION - executable = go.declare_file(go, name=name, ext=extension) + if not executable: + extension = go.exe_extension + if go.mode.link == LINKMODE_C_SHARED: + name = "lib" + name # shared libraries need a "lib" prefix in their name + extension = go.shared_extension + elif go.mode.link == LINKMODE_C_ARCHIVE: + extension = ARCHIVE_EXTENSION + executable = go.declare_file(go, name=name, ext=extension) go.link(go, archive=archive, executable=executable, diff --git a/go/private/rules/binary.bzl b/go/private/rules/binary.bzl index dff084562b..c32cccaaca 100644 --- a/go/private/rules/binary.bzl +++ b/go/private/rules/binary.bzl @@ -58,13 +58,20 @@ def _go_binary_impl(ctx): name = ctx.attr.basename if not name: name = ctx.label.name + executable = None + if ctx.attr.out: + # Use declare_file instead of attr.output(). When users set output files + # directly, Bazel warns them not to use the same name as the rule, which is + # the common case with go_binary. + executable = ctx.actions.declare_file(ctx.attr.out) archive, executable = go.binary(go, name = name, source = source, gc_linkopts = gc_linkopts(ctx), - linkstamp=ctx.attr.linkstamp, - version_file=ctx.version_file, - info_file=ctx.info_file, + linkstamp = ctx.attr.linkstamp, + version_file = ctx.version_file, + info_file = ctx.info_file, + executable = executable, ) return [ library, source, archive, @@ -140,6 +147,7 @@ go_binary = go_rule( "linkstamp": attr.string(), "x_defs": attr.string_dict(), "linkmode": attr.string(values=LINKMODES, default=LINKMODE_NORMAL), + "out": attr.string(), }, executable = True, ) @@ -162,6 +170,7 @@ go_tool_binary = go_rule( "linkstamp": attr.string(), "x_defs": attr.string_dict(), "linkmode": attr.string(values=LINKMODES, default=LINKMODE_NORMAL), + "out": attr.string(), "_hostonly": attr.bool(default=True), }, executable = True, diff --git a/go/toolchains.rst b/go/toolchains.rst index 26c7212944..83a2915ee6 100644 --- a/go/toolchains.rst +++ b/go/toolchains.rst @@ -559,9 +559,10 @@ binary ~~~~~~ This emits actions to compile and link Go code into a binary. -It supports embedding, cgo dependencies, coverage, and assembling and packing .s files. +It supports embedding, cgo dependencies, coverage, and assembling and packing +.s files. -It returns GoLibrary_. +It returns a tuple containing GoArchive_ and the output executable file. +--------------------------------+-----------------------------+-----------------------------------+ | **Name** | **Type** | **Default value** | @@ -570,9 +571,9 @@ It returns GoLibrary_. +--------------------------------+-----------------------------+-----------------------------------+ | This must be the same GoContext object you got this function from. | +--------------------------------+-----------------------------+-----------------------------------+ -| :param:`name` | :type:`string` | |mandatory| | +| :param:`name` | :type:`string` | :value:`""` | +--------------------------------+-----------------------------+-----------------------------------+ -| The base name of the generated binaries. | +| The base name of the generated binaries. Required if :param:`executable` is not given. | +--------------------------------+-----------------------------+-----------------------------------+ | :param:`source` | :type:`GoSource` | |mandatory| | +--------------------------------+-----------------------------+-----------------------------------+ @@ -580,13 +581,25 @@ It returns GoLibrary_. +--------------------------------+-----------------------------+-----------------------------------+ | :param:`gc_linkopts` | :type:`string_list` | :value:`[]` | +--------------------------------+-----------------------------+-----------------------------------+ -| Basic link options. | +| Go link options. | +--------------------------------+-----------------------------+-----------------------------------+ -| :param:`x_defs` | :type:`map` | :value:`{}` | +| :param:`linkstamp` | :type:`string` | :value:`None` | +--------------------------------+-----------------------------+-----------------------------------+ -| Link defines, including build stamping ones. | +| Optional link stamp. See link_. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`version_file` | :type:`File` | :value:`None` | ++--------------------------------+-----------------------------+-----------------------------------+ +| Version file used for link stamping. See link_. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`info_file` | :type:`File` | :value:`None` | ++--------------------------------+-----------------------------+-----------------------------------+ +| Info file used for link stamping. See link_. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`executable` | :type:`File` | :value:`None` | ++--------------------------------+-----------------------------+-----------------------------------+ +| Optional output file to write. If not set, ``binary`` will generate an output | +| file name based on ``name``, the target platform, and the link mode. | +--------------------------------+-----------------------------+-----------------------------------+ - compile ~~~~~~~ diff --git a/tests/core/go_binary/BUILD.bazel b/tests/core/go_binary/BUILD.bazel new file mode 100644 index 0000000000..1cc16891b8 --- /dev/null +++ b/tests/core/go_binary/BUILD.bazel @@ -0,0 +1,15 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_test") + +test_suite(name = "go_binary") + +go_test( + name = "go_default_test", + srcs = ["out_test.go"], + data = [":custom_bin"], +) + +go_binary( + name = "custom_bin", + srcs = ["custom_bin.go"], + out = "alt_bin", +) diff --git a/tests/core/go_binary/README.rst b/tests/core/go_binary/README.rst new file mode 100644 index 0000000000..7922daa261 --- /dev/null +++ b/tests/core/go_binary/README.rst @@ -0,0 +1,12 @@ +Basic go_binary functionality +============================= + +.. _go_binary: /go/core.rst#_go_binary + +Tests to ensure the basic features of go_binary are working as expected. + +out_test +-------- + +Test that a go_binary_ rule can write its executable file with a custom name +in the package directory (not the mode directory). diff --git a/tests/core/go_binary/custom_bin.go b/tests/core/go_binary/custom_bin.go new file mode 100644 index 0000000000..da29a2cadf --- /dev/null +++ b/tests/core/go_binary/custom_bin.go @@ -0,0 +1,4 @@ +package main + +func main() { +} diff --git a/tests/core/go_binary/out_test.go b/tests/core/go_binary/out_test.go new file mode 100644 index 0000000000..7c6ba7f335 --- /dev/null +++ b/tests/core/go_binary/out_test.go @@ -0,0 +1,13 @@ +package main + +import ( + "os" + "testing" +) + +func TestCustomBinaryName(t *testing.T) { + _, err := os.Stat("alt_bin") + if err != nil { + t.Error(err) + } +}