Description
What is the use case for bind()? I can't think of one. Even in situations where there are multiple ABI-compatible implementations of a library (e.g. OpenSSL, BoringSSL, etc.) this problem could still be solved by using vanilla externals.
Most Bazel projects don't seem to use bind(). The ones that do, it seems to have caused problems.
For example, the protobuf repository, rather than defining a protobuf_repositories()
function, simply uses //external:foo
for every single target upon which it depends, thereby punting the burden defining bind() rules not only for every single external, but every target within those externals.
As a result, the TensorFlow workspace.bzl file has developed a cargo cult pattern where superfluous bindings will be added, because I don't think people really understand what bind() does.
What is especially suboptimal is that the bind() namespace overlaps with the external repository namespace. We can't name externals like "six" to be "@six" because the protobuf BUILD file asked us for //external:six
. So we don't have a choice. We have to name it @six_archive
, which hurts readability. It would have been more optimal if the protobuf BUILD file should have just asked for @six//:six
.
It would be nice if we could retire bind() and help projects like protobuf migrate to the foo_repositories() model that official Bazel projects use. We could recommend as a best practice the technique that is employed by the Closure Rules repositories.bzl file.
def closure_repositories(
omit_foo=False,
omit_bar=False):
if not omit_foo:
foo()
if not omit_bar:
bar()
def foo():
native.maven_jar(name = "foo", ...)
def bar():
native.maven_jar(name = "bar", ...)
This gives dependent Bazel projects the power to schlep in transitive Closure Rules dependencies using either a whitelist or blacklist model. For example, one project that uses Closure Rules has the following in its WORKSPACE file:
http_archive(
name = "io_bazel_rules_closure",
sha256 = "7d75688c63ac09a55ca092a76c12f8d1e9ee8e7a890f3be6594a4e7d714f0e8a",
strip_prefix = "rules_closure-b8841276e73ca677c139802f1168aaad9791dec0",
url = "http://bazel-mirror.storage.googleapis.com/github.com/bazelbuild/rules_closure/archive/b8841276e73ca677c139802f1168aaad9791dec0.tar.gz", # 2016-10-02
)
load("@io_bazel_rules_closure//closure:defs.bzl", "closure_repositories")
closure_repositories(
omit_gson = True,
omit_guava = True,
omit_icu4j = True,
omit_json = True,
omit_jsr305 = True,
omit_jsr330_inject = True,
)
Because it directly depends on those transitive dependencies and wants to specify them on its own.
I think this is a much more desirable and flexible pattern than bind().