I'm attempting to use Bazel's Protocol Buffer Rules to compile (generate) Python language bindings and any dependencies. The layout of my project is simple, with a single directory, proto
, containing the .proto
file and BUILD
file.
WORKSPACE
BUILD.six
|-- proto
| |-- example.proto
| |-- BUILD
My WORKSPACE
file:
workspace(name = "com_example")
http_archive(
name = "com_google_protobuf",
strip_prefix = "protobuf-3.4.1",
urls = ["https://github.com/google/protobuf/archive/v3.4.1.zip"],
)
new_http_archive(
name = "six_archive",
build_file = "six.BUILD",
url = "https://pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz",
)
bind(
name = "six",
actual = "@six_archive//:six",
)
In my WORKSPACE
file, the expected SHA-256 hash of the file downloaded has been omitted for readability. The http_archive WORKSPACE rule is used to since the ProtoBuf GitHub repo contains Bazel WORKSPACE
and BUILD
files.
The new_http_archive must be used for the six library since it's not a Bazel workspace. Also worth noting that Bazel transitive dependencies must be provided in my WORKSPACE
file (from Bazel documentation):
Bazel only reads dependencies listed in your WORKSPACE file. If your project (A) depends on another project (B) which list a dependency on a third project (C) in its WORKSPACE file, you'll have to add both B and C to your project's WORKSPACE file.
six.BUILD
is taken directly from the repo and saved locally:
My BUILD
file
load("@com_google_protobuf//:protobuf.bzl", "py_proto_library")
py_proto_library(
name = "py",
use_grpc_plugin = True,
deps = [
"@com_google_protobuf//:protobuf_python",
":example_proto",
],
visibility = ["//visibility:public"],
# protoc = "@com_google_protobuf//:protoc",
)
proto_library(
name = "example_proto",
srcs = ["example.proto"],
)
The problem arrises when building:
bazel build //proto:py
Output (formatted for readability):
proto/BUILD:3:1:
no such target '//:protobuf_python':
target 'protobuf_python' not declared in package '' defined by BUILD and referenced by '//proto:py'.
ERROR: Analysis of target '//proto:py' failed; build aborted.
However, building the external dependency from my command line works:
bazel build @com_google_protobuf//:protobuf_python
Output (truncated for readability):
INFO: Found 1 target...
...
INFO: Elapsed time: 51.577s, Critical Path: 8.63s
The protobuf_python
target is clearly defined and public:
The problem is that your target (//proto:py) depends on //:protobuf_python, not @com_gooogle_protobuf//:protobuf_python. You can confirm this with bazel query.
You can see it in the deps list. So now the question is, why does it depend on that? You certainly didn't set that anywhere. The answer is that, since py_proto_library is a macro, it can do whatever it wants.
In particular, these lines of the macro are causing you trouble:
https://github.com/google/protobuf/blob/6032746882ea48ff6d983df8cb77e2ebf399bf0c/protobuf.bzl#L320 https://github.com/google/protobuf/blob/6032746882ea48ff6d983df8cb77e2ebf399bf0c/protobuf.bzl#L373-L374
py_proto_library has an attribute called default_runtime that it appends to the deps list. The default value is ":protobuf_python". But that only works if you use the macro in the same repository that declares protobuf_python.
So, you can fix this by setting
default_runtime = "@com_google_protobuf//:protobuf_python"
in your py_proto_librarys attributes.