Skip to content

Commit bb42937

Browse files
committed
Working demonstration of imports for C++. Checkpointing.
1 parent 50cfe68 commit bb42937

File tree

10 files changed

+150
-52
lines changed

10 files changed

+150
-52
lines changed

bzl/base/class.bzl

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ def build_generated_files(lang, self):
3333
fail("Empty proto file input list.")
3434

3535
for srcfile in self.get("srcs", []):
36-
basename = srcfile.basename[:-len(".proto")]
36+
base = srcfile.basename[:-len(".proto")]
3737
for ext in exts:
38-
pbfile = ctx.new_file(srcfile, basename + ext)
38+
pbfile = ctx.new_file(base + ext)
3939
self["provides"] += [pbfile]
4040

4141

@@ -54,11 +54,42 @@ def build_generated_filenames(lang, self):
5454
self["outs"] += [srcfile.rsplit('.', 1)[0] + ext]
5555

5656

57-
def build_imports(lang, self):
57+
def build_paths(lang, self):
5858
"""Build the list of imports"""
5959
ctx = self["ctx"]
6060
if ctx:
61-
self["imports"] = self.get("imports", []) + ctx.attr.imports
61+
self["paths"] = self.get("paths", []) + ctx.attr.paths
62+
63+
def build_imports(lang, self):
64+
"""Copy any named proto files in the imports to the genfiles area to make visible to protoc. Not sure this is necessary anymore."""
65+
ctx = self["ctx"]
66+
if not ctx:
67+
fail("Bazel context is required for build_imports")
68+
#print("ctx.attr.imports: %s" % type(ctx.attr.imports))
69+
for target in ctx.attr.imports:
70+
for srcfile in target.files:
71+
print("srcfile: %s" % srcfile.path)
72+
dstfile = ctx.new_file(srcfile.path)
73+
#dstfile = ctx.new_file(srcfile.path)
74+
# By declaring that the proto action (happening later)
75+
# depends on these files, we ensure that the
76+
# CpImportToPackageGenfile action is run. Without this
77+
# linkage, bazel assumes the action isn't required.
78+
self["requires"] += [dstfile]
79+
if ctx.attr.verbose > 1:
80+
print("Copying import %s --> %s" % (srcfile.path, dstfile.path))
81+
ctx.action(mnemonic = "CpImportToPackageGenfiles",
82+
inputs = [srcfile],
83+
outputs = [dstfile],
84+
arguments = [srcfile.path, dstfile.path],
85+
command = "cp $1 $2")
86+
# These probably need to be compiled also. Nope: if you
87+
# try this you get "inconsistent package names" from
88+
# https://github.com/golang/protobuf/blob/1687f003bf0280bd6182a5a1c7241856b269a6c0/protoc-gen-go/generator/generator.go#L750
89+
#self["srcs"] += [dstfile]
90+
91+
#self["go_plugin_options"] = self.get("go_plugin_options", []) + ["M" + srcfile.path + "="]
92+
self["paths"] += [self["outdir"]]
6293

6394
def build_plugin_out(name, key, lang, self):
6495
#print("build_plugin_out(%s, %s)" % (name, key))
@@ -67,7 +98,7 @@ def build_plugin_out(name, key, lang, self):
6798
plugin = getattr(lang, key)
6899
opts = getattr(plugin, "default_options", [])
69100
opts += self.get(key + "_plugin_options", [])
70-
outdir = self["gendir"]
101+
outdir = self["outdir"]
71102
if opts:
72103
outdir = ",".join(opts) + ":" + outdir
73104
self["args"] += ["--%s_out=%s" % (name, outdir)]
@@ -133,7 +164,7 @@ def build_protobuf_invocation(lang, self):
133164
def build_protoc_command(lang, self):
134165
"""Build a command list required for genrule execution"""
135166
self["cmd"] += ["$(location %s)" % self["protoc"]]
136-
self["cmd"] += ["-I" + i for i in self["imports"]]
167+
self["cmd"] += ["--proto_path=" + i for i in self["paths"]]
137168
self["cmd"] += self["args"]
138169
self["cmd"] += ["$(location " + proto + ")" for proto in self["protos"]]
139170

@@ -188,6 +219,7 @@ CLASS = struct(
188219
build_generated_filenames = build_generated_filenames,
189220
build_imports = build_imports,
190221
build_inputs = build_inputs,
222+
build_paths = build_paths,
191223
build_tools = build_tools,
192224
build_protobuf_invocation = build_protobuf_invocation,
193225
build_protobuf_out = build_protobuf_out,

bzl/cpp/rules.bzl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ cc_proto_compile = implement(["cpp"])
77
def cc_proto_library(
88
name,
99
protos,
10-
copy_protos_to_genfiles = True,
10+
copy_protos_to_genfiles = False,
1111
deps = [],
1212
grpc_plugin = None,
1313
grpc_plugin_options = [],
1414
imports = [],
1515
lang = CPP,
16+
paths = [],
1617
proto_compile = cc_proto_compile,
1718
protobuf_plugin_options = [],
1819
protobuf_plugin = None,
@@ -33,6 +34,7 @@ def cc_proto_library(
3334
args["gen_protobuf_" + lang.name + "_plugin"] = protobuf_plugin
3435
args["gen_" + lang.name + "_plugin_options"] = protobuf_plugin_options
3536
args["gen_grpc_" + lang.name + "_plugin"] = grpc_plugin
37+
args["paths"] = paths
3638
args["protoc"] = protoc
3739
args["protos"] = protos
3840
args["verbose"] = verbose

bzl/go/rules.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ def go_proto_library(
1313
grpc_plugin_options = [],
1414
imports = [],
1515
lang = GO,
16+
paths = [],
1617
proto_compile = go_proto_compile,
1718
protobuf_plugin_options = [],
1819
protobuf_plugin = None,
@@ -33,6 +34,7 @@ def go_proto_library(
3334
args["gen_protobuf_" + lang.name + "_plugin"] = protobuf_plugin
3435
args["gen_" + lang.name + "_plugin_options"] = protobuf_plugin_options
3536
args["gen_grpc_" + lang.name + "_plugin"] = grpc_plugin
37+
args["paths"] = paths
3638
args["protoc"] = protoc
3739
args["protos"] = protos
3840
args["verbose"] = verbose

bzl/java/class.bzl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ def _build_generated_files(lang, self):
1313
protojar = ctx.new_file(srcjar, "%s.jar" % basename)
1414
self["protojar"] = protojar
1515
# This will generate the jar inthe source tree itself
16-
#self["gendir"] = protojar.short_path
16+
#self["outdir"] = protojar.short_path
1717

1818
# This will generate the jar in the BINDIR
19-
self["gendir"] = protojar.path
19+
self["outdir"] = protojar.path
2020
self["provides"] += [protojar]
2121

2222

bzl/protoc.bzl

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def protoc_genrule(name,
7878

7979
invoke("build_generated_filenames", lang, self)
8080
invoke("build_tools", lang, self)
81-
invoke("build_imports", lang, self)
81+
invoke("build_paths", lang, self)
8282
invoke("build_protobuf_invocation", lang, self)
8383
invoke("build_protobuf_out", lang, self)
8484
if with_grpc:
@@ -96,20 +96,11 @@ def protoc_genrule(name,
9696
return struct(**self)
9797

9898

99-
def _get_path(ctx, path):
100-
if ctx.label.workspace_root:
101-
return ctx.label.workspace_root + '/' + path
102-
else:
103-
return path
104-
105-
10699
def _get_gendir(ctx):
107100
if ctx.attr.output_to_genfiles:
108-
outdir = ctx.var["GENDIR"]
101+
return ctx.var["GENDIR"]
109102
else:
110-
outdir = ctx.var["BINDIR"]
111-
112-
return outdir + "/" + ctx.label.package
103+
return ctx.var["BINDIR"]
113104

114105

115106
def _execute_rule(self):
@@ -118,13 +109,16 @@ def _execute_rule(self):
118109
fail("Bazel context required for rule execution")
119110

120111
srcfiles = []
121-
for src in self["srcs"]:
122-
srcfiles += [src.path]
123-
112+
for src in self["srcfilenames"]:
113+
srcfiles += [src]
114+
#srcfiles += [src.path]
124115

125116
#self["args"] += ["--descriptor_set_out=%s" % (descriptor_set_file.path)]
126117

127-
arguments = list(set(self["args"] + ["-I" + i for i in self["imports"]] + srcfiles))
118+
arglist = list(set(self["args"]))
119+
pathlist = ["--proto_path=" + i for i in set(self["paths"])]
120+
121+
arguments = arglist + pathlist + srcfiles
128122
inputs = list(set(self["requires"]))
129123
outputs = list(set(self["provides"] + ctx.outputs.outs))
130124

@@ -166,22 +160,33 @@ def _build_source_files(ctx, self):
166160
arguments = [srcfile.path, protofile.path],
167161
command = "cp $1 $2")
168162
self["srcs"] += [protofile]
169-
self["imports"] += [protofile.dirname]
163+
self["srcfilenames"] += [srcfile.short_path]
170164
else:
171165
if self["verbose"]:
172166
print("No Copy source files.")
173167
for srcfile in ctx.files.protos:
174168
self["srcs"] += [srcfile]
175-
self["imports"] += [srcfile.dirname]
169+
self["srcfilenames"] += [srcfile.short_path]
170+
171+
# This is the key to enable imports: protoc can see the entire
172+
# source tree from the workspace root.
173+
self["paths"] += ["."]
176174

177175
def _protoc_rule_impl(ctx):
178176

177+
gendir = _get_gendir(ctx)
178+
outdir = gendir
179+
#outdir = gendir + "/" + ctx.label.package
180+
179181
self = {
180182
"ctx": ctx,
181-
"gendir": _get_gendir(ctx),
183+
"gendir": gendir,
184+
"outdir": outdir,
182185
"imports": [],
186+
"paths": [],
183187
"args": [],
184188
"srcs": [],
189+
"srcfilenames": [],
185190
"requires": [],
186191
"copy_protos_to_genfiles": getattr(ctx.attr, "copy_protos_to_genfiles", False),
187192
"provides": [],
@@ -192,11 +197,12 @@ def _protoc_rule_impl(ctx):
192197

193198
# Propogate proto deps: TODO: this is completely untested.
194199
for dep in ctx.attr.deps:
195-
self["imports"] += dep.proto.imports
196-
self["requires"] += dep.proto.deps
197-
self["srcs"] += dep.proto.srcs
200+
if hasattr(dep, "proto"):
201+
self["paths"] += dep.proto.paths
202+
self["requires"] += dep.proto.deps
203+
self["srcs"] += dep.proto.srcs
198204

199-
# Copy source files over to gendir
205+
# Copy source files over to outdir
200206
_build_source_files(ctx, self)
201207

202208
# Make a list of languages that were specified for this run
@@ -211,6 +217,7 @@ def _protoc_rule_impl(ctx):
211217

212218
invoke("build_generated_files", lang, self)
213219
invoke("build_imports", lang, self)
220+
invoke("build_paths", lang, self)
214221
invoke("build_protobuf_invocation", lang, self)
215222
invoke("build_protobuf_out", lang, self)
216223
if self["with_grpc"]:
@@ -230,6 +237,7 @@ def _protoc_rule_impl(ctx):
230237
proto=struct(
231238
srcs = set(self["srcs"]),
232239
imports = self["imports"],
240+
paths = self["paths"],
233241
deps = self["requires"],
234242
),
235243
)
@@ -254,11 +262,21 @@ def implement(spec):
254262

255263
# ? How to deps interact here? Don't understand this. Provider
256264
# aspect is "proto".
257-
attrs["deps"] = attr.label_list(providers = ["proto"])
258-
259-
# Additional include options to protoc. These should be
260-
# directories. TODO(user): should this be typed as directory only?
261-
attrs["imports"] = attr.string_list()
265+
#attrs["deps"] = attr.label_list(providers = ["proto"])
266+
attrs["deps"] = attr.label_list()
267+
268+
# Options to be passed to protoc as --proto_path. Differs from
269+
# imports in that these are raw strings rather than labels.
270+
attrs["paths"] = attr.string_list()
271+
272+
# Protos that should be made available for proto imports. These are
273+
# not added as options but rather copied over to the sandbox where
274+
# protoc is run, making them available for import. TODO: is this
275+
# really needed? Test it by using the descriptor protos from
276+
# google/protobuf.
277+
attrs["imports"] = attr.label_list(
278+
allow_files = FileType([".proto"]),
279+
)
262280

263281
# The list of files the rule generates. How is this actually being
264282
# used?
@@ -281,10 +299,9 @@ def implement(spec):
281299
# Generate the descriptor? Shouldn't we just always generate this?
282300
#attrs["with_descriptor"] = attr.bool()
283301

284-
# Implemntation detail that varies between output languages. JAVA:
285-
# does not matter.
302+
# Implementation detail that varies between output languages.
286303
attrs["copy_protos_to_genfiles"] = attr.bool(
287-
default = True,
304+
default = False,
288305
)
289306

290307
# Flag that sets gen_grpc_{lang} to true for all languages.

examples/helloworld/proto/BUILD

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,34 @@ filegroup(
1515
# Go proto library implementation cannot accept proto filesets from
1616
# say, a filegroup. It needs to be an explicit filename. This is the
1717
# reason this rule is in the proto dir.
18-
go_proto_library(
19-
name = "go",
20-
#name = "go_default_library", a viable alternative
21-
protos = ["helloworld.proto"],
22-
verbose = 0,
23-
with_grpc = True,
24-
)
18+
# go_proto_library(
19+
# name = "go",
20+
# protos = ["helloworld.proto"],
21+
# imports = [
22+
# "//examples/proto:srcs",
23+
# ],
24+
# verbose = 2,
25+
# with_grpc = True,
26+
# )
2527

2628
# cc_proto_library implementation cannot accept proto filesets from
2729
# say, a filegroup. It needs to be an explicit filename. This is the
2830
# reason this rule is in the proto dir.
2931
cc_proto_library(
3032
name = "cpp",
3133
protos = ["helloworld.proto"],
34+
deps = [
35+
"//examples/proto:cpplib",
36+
],
3237
verbose = 0,
3338
with_grpc = True,
3439
)
3540

36-
grpc_gateway_proto_library(
37-
name = "gw",
38-
protos = ["helloworld_gateway.proto"],
39-
verbose = 0,
40-
)
41+
# grpc_gateway_proto_library(
42+
# name = "gw",
43+
# protos = ["helloworld_gateway.proto"],
44+
# verbose = 0,
45+
# )
4146

4247
# py_proto_library(
4348
# name = "pylib",

examples/helloworld/proto/helloworld.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ option java_multiple_files = true;
55
option java_package = "org.pubref.rules_protobuf.examples.helloworld";
66
option java_outer_classname = "HelloWorldProto";
77

8+
import "examples/proto/common.proto";
9+
810
package helloworld;
911

1012
// The greeting service definition.
@@ -16,6 +18,7 @@ service Greeter {
1618
// The request message containing the user's name.
1719
message HelloRequest {
1820
string name = 1;
21+
common.Config config = 2;
1922
}
2023

2124
// The response message containing the greetings

examples/proto/BUILD

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package(default_visibility = ["//visibility:public"])
2+
3+
load("//bzl:go/rules.bzl", "go_proto_library")
4+
load("//bzl:cpp/rules.bzl", "cc_proto_library")
5+
6+
filegroup(
7+
name = "srcs",
8+
srcs = [
9+
"common.proto",
10+
],
11+
)
12+
13+
go_proto_library(
14+
name = "go_default_library",
15+
protos = ["common.proto"],
16+
)
17+
18+
cc_proto_library(
19+
name = "cpplib",
20+
protos = ["common.proto"],
21+
verbose = 2,
22+
)

examples/proto/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
This directory contains proto files that are common to different
2+
examples. At the moment, there is only one (helloworld). This
3+
permits the testing of proto imports.

0 commit comments

Comments
 (0)