Skip to content

Commit

Permalink
go: use configuration transitions instead of aspect (bazel-contrib#2414)
Browse files Browse the repository at this point in the history
This changes how the goos, goarch, race, msan, static, and pure
attributes of go_binary and go_test are implemented.

Previously, the go_binary and go_test rules used an aspect on the deps
and embed attributes. If any of the mode attributes listed above were
set, the aspect declared additional output files and actions to
generate them for the specified configuration. This approach had two
significant problems. First, the aspect caused the analysis to be
performed twice, wasting time and memory even in the case
where no cross-compilation was needed. Second, the aspect was not
compatible with conditional dependencies specified with select
expressions: aspects run on the configured target graph, but the mode
attributes could not affect Bazel's configuration.

This change deletes the aspect and implements these attributes using a
different mechanism: build settings and configuration transitions.

A new package is added //go/config with a build setting for each
attribute. Most settings are flags that may be set on the
command-line. This is an alternative to --feature flags, which will be
deprecated and eventually removed.

The target //:go_config gathers build settings relevant to Go and
provides a GoContextInfo (private).

The target //:go_context_data depends on //:go_config, //:stdlib,
//:nogo, and a few other standard dependencies. go_binary and go_test
rules no longer need to depend on these targets directly. Go rules
should now only need to depend on //:go_context_data and the Go
toolchain. Unfortunately, neither //:go_context_data nor //:go_config
can be part of the toolchain because the toolchain is always analyzed
for the execution configuration, not the target configuration.

Because of the simplified dependencies, the go_rule function is no
longer needed by most rules. This change makes it possible to
deprecate it.

Fixes bazel-contrib#1351
Fixes bazel-contrib#2219
Updates bazel-contrib#2302
  • Loading branch information
Jay Conrod authored Apr 17, 2020
1 parent f9a4fb1 commit 3edc6d5
Show file tree
Hide file tree
Showing 38 changed files with 967 additions and 600 deletions.
86 changes: 69 additions & 17 deletions BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
load("@io_bazel_rules_go//go/private:tools/lines_sorted_test.bzl", "lines_sorted_test")
load("@io_bazel_rules_go//go/private:rules/nogo.bzl", "nogo")
load("@io_bazel_rules_go//go:def.bzl", "TOOLS_NOGO")
load("@io_bazel_rules_go//go/private:rules/info.bzl", "go_info")
load("@io_bazel_rules_go//go/private:context.bzl", "cgo_context_data", "go_context_data")
load("@io_bazel_rules_go//go/private:rules/stdlib.bzl", "stdlib")
load(
"@io_bazel_rules_go//go/private:tools/lines_sorted_test.bzl",
"lines_sorted_test",
)
load(
"@io_bazel_rules_go//go/private:rules/nogo.bzl",
"nogo",
)
load(
"@io_bazel_rules_go//go/private:rules/info.bzl",
"go_info",
)
load(
"@io_bazel_rules_go//go:def.bzl",
"TOOLS_NOGO",
)
load(
"@io_bazel_rules_go//go/private:context.bzl",
"cgo_context_data",
"cgo_context_data_proxy",
"go_config",
"go_context_data",
)
load(
"@io_bazel_rules_go//go/private:rules/stdlib.bzl",
"stdlib",
)

stdlib(
name = "stdlib",
cgo_context_data = select({
"//go/platform:internal_cgo_off": None,
"//conditions:default": ":cgo_context_data",
}),
visibility = ["//visibility:public"],
)

Expand All @@ -33,25 +58,52 @@ nogo(
go_context_data(
name = "go_context_data",
cgo_context_data = select({
"@io_bazel_rules_go//go/platform:internal_cgo_off": None,
"//go/platform:internal_cgo_off": None,
"//conditions:default": ":cgo_context_data",
}),
stamp = select({
"@io_bazel_rules_go//go/private:stamp": True,
"//conditions:default": False,
}),
strip = select({
"@io_bazel_rules_go//go/private:strip-always": "always",
"@io_bazel_rules_go//go/private:strip-sometimes": "sometimes",
"@io_bazel_rules_go//go/private:strip-never": "never",
}),
coverdata = "//go/tools/coverdata",
go_config = ":go_config",
nogo = "@io_bazel_rules_nogo//:nogo",
stdlib = ":stdlib",
visibility = ["//visibility:public"],
)

# cgo_context_data collects information about the C/C++ toolchain.
# go_toolchains may depend on this in order to support cgo.
# go_context_data depends if cgo is enabled in the target configuration.
cgo_context_data(
name = "cgo_context_data",
visibility = ["//visibility:private"],
)

# cgo_context_data_proxy depends on cgo_context_data if cgo is enabled and
# forwards its provider. Rule attributes may depend on this, since they cannot
# use select.
cgo_context_data_proxy(
name = "cgo_context_data_proxy",
actual = select({
"//go/platform:internal_cgo_off": None,
"//conditions:default": ":cgo_context_data",
}),
visibility = ["//visibility:public"],
)

# go_config collects information about build settings in the current
# configuration. go_context_data depends on this so that rules don't need
# to depend on all build settings directly.
go_config(
name = "go_config",
debug = "//go/config:debug",
gotags = "//go/config:tags",
linkmode = "//go/config:linkmode",
msan = "//go/config:msan",
pure = "//go/config:pure",
race = "//go/config:race",
stamp = select({
"//go/private:stamp": True,
"//conditions:default": False,
}),
static = "//go/config:static",
strip = "//go/config:strip",
visibility = ["//visibility:public"],
)

Expand Down
16 changes: 8 additions & 8 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ Go rules for Bazel_
.. _Overriding dependencies: go/dependencies.rst#overriding-dependencies
.. _Proto dependencies: go/dependencies.rst#proto-dependencies
.. _Proto rules: proto/core.rst
.. _Protocol buffers: proto/core.rst
.. _Running Bazel Tests on Travis CI: https://kev.inburke.com/kevin/bazel-tests-on-travis-ci/
.. _Toolchains: go/toolchains.rst
.. _Using rules_go on Windows: windows.rst
.. _bazel-go-discuss: https://groups.google.com/forum/#!forum/bazel-go-discuss
.. _configuration transition: https://docs.bazel.build/versions/master/skylark/lib/transition.html
.. _gRPC dependencies: go/dependencies.rst#grpc-dependencies
.. _gazelle update-repos: https://github.com/bazelbuild/bazel-gazelle#update-repos
.. _gazelle: https://github.com/bazelbuild/bazel-gazelle
Expand All @@ -27,7 +29,6 @@ Go rules for Bazel_
.. _korfuri/bazel-travis Use Bazel with Travis CI: https://github.com/korfuri/bazel-travis
.. _nogo build-time static analysis: go/nogo.rst
.. _nogo: go/nogo.rst
.. _Protocol buffers: proto/core.rst
.. _rules_go and Gazelle roadmap: https://github.com/bazelbuild/rules_go/wiki/Roadmap

.. Go rules
Expand Down Expand Up @@ -599,13 +600,12 @@ dependencies with ``select`` expressions (Gazelle does this automatically).
}),
)
rules_go can generate pure Go binaries for any platform the Go SDK supports.

In some cases, you may want to set the ``goos`` and ``goarch`` attributes of
``go_binary``. This will cross-compile a binary for a specific platform.
This is necessary when you need to produce multiple binaries for different
platforms in a single build. However, note that ``select`` expressions will
not work correctly when using these attributes.
To build a specific `go_binary`_ or `go_test`_ target for a target platform,
set the ``goos`` and ``goarch`` attributes on that rule. This is useful for
producing multiple binaries for different platforms in a single build.
You can equivalently depend on a `go_binary`_ or `go_test`_ rule through
a Bazel `configuration transition`_ on ``//command_line_option:platforms``
(there are problems with this approach prior to rules_go 0.23.0).

How do I use different versions of dependencies?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
2 changes: 1 addition & 1 deletion WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")

go_rules_dependencies()
go_rules_dependencies(is_rules_go = True)

go_register_toolchains()

Expand Down
1 change: 1 addition & 0 deletions go/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ filegroup(
name = "all_files",
testonly = True,
srcs = glob(["**"]) + [
"//go/config:all_files",
"//go/platform:all_files",
"//go/toolchain:all_files",
"//go/tools:all_files",
Expand Down
66 changes: 66 additions & 0 deletions go/config/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
load(
"@bazel_skylib//rules:common_settings.bzl",
"bool_flag",
"bool_setting",
"string_flag",
"string_list_flag",
)
load(
"//go/private:mode.bzl",
"LINKMODE_NORMAL",
)

bool_flag(
name = "static",
build_setting_default = False,
visibility = ["//visibility:public"],
)

bool_flag(
name = "race",
build_setting_default = False,
visibility = ["//visibility:public"],
)

bool_flag(
name = "msan",
build_setting_default = False,
visibility = ["//visibility:public"],
)

bool_flag(
name = "pure",
build_setting_default = False,
visibility = ["//visibility:public"],
)

bool_setting(
name = "strip",
build_setting_default = False,
visibility = ["//visibility:public"],
)

bool_flag(
name = "debug",
build_setting_default = False,
visibility = ["//visibility:public"],
)

string_flag(
name = "linkmode",
build_setting_default = LINKMODE_NORMAL,
visibility = ["//visibility:public"],
)

string_list_flag(
name = "tags",
build_setting_default = [],
visibility = ["//visibility:public"],
)

filegroup(
name = "all_files",
testonly = True,
srcs = glob(["**"]),
visibility = ["//visibility:public"],
)
22 changes: 0 additions & 22 deletions go/core.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1096,25 +1096,3 @@ OS-architecture pair. For a full list, run this command:
$ bazel query 'kind(config_setting, @io_bazel_rules_go//go/platform:all)'
`Gazelle`_ will generate dependencies in this format automatically.

Note on goos and goarch attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

It is possible to cross-compile ``go_binary`` and ``go_test`` targets by
setting the ``goos`` and ``goarch`` attributes to the target platform. These
attributes were added for projects that cross-compile binaries for multiple
platforms in the same build, then package the resulting executables.

Bazel does not have a native understanding of the ``goos`` and ``goarch``
attributes, so values do not affect `select`_ expressions. This means if you use
these attributes with a target that has any transitive platform-specific
dependencies, ``select`` may choose the wrong set of dependencies. Consequently,
if you use ``goos`` or ``goarch`` attributes, you will not be able to safely
generate build files with Gazelle or ``go_repository``.

Additionally, setting ``goos`` and ``goarch`` will not automatically disable
cgo. You should almost always set ``pure = "on"`` together with these
attributes.

Because of these limitations, it's almost always better to cross-compile by
setting ``--platforms`` on the command line instead.
Loading

0 comments on commit 3edc6d5

Please sign in to comment.