Skip to content
File

Blob: build/js_capnp_library.bzl

5.3 KB
1"""
2Bazel rule to compile .capnp files into JS/TS using capnp-es.
3Based on https://github.com/capnproto/capnproto/blob/3b2e368cecc4b1419b40c5970d74a7a342224fac/c++/src/capnp/cc_capnp_library.bzl.
4"""
5 
6load("@aspect_rules_js//js:defs.bzl", "js_library")
7 
8capnp_provider = provider("Capnproto Provider", fields = {
9 "includes": "includes for this target (transitive)",
10 "inputs": "src + data for the target",
11 "src_prefix": "src_prefix of the target",
12})
13 
14def _workspace_path(label, path):
15 if label.workspace_root == "":
16 return path
17 return label.workspace_root + "/" + path
18 
19def _capnp_plugin_gen(ctx, output_format, out_dir, inputs, includes, src_prefix, system_include):
20 """Generate output files of the given output_format ("js" or "ts")"""
21 
22 if not (output_format == "js" or output_format == "ts"):
23 fail("Only js and ts output formats are supported")
24 
25 # Filter the outputs to generate by requested output_format
26 outputs = [out for out in ctx.outputs.outs if out.path.endswith(".%s" % output_format)]
27 if (not outputs):
28 return
29 
30 plugin_name = "_%s_plugin" % output_format
31 plugin_executable = getattr(ctx.executable, plugin_name)
32 plugin_files = getattr(ctx.files, plugin_name)
33 
34 label = ctx.label
35 
36 js_out = "-o%s:%s" % (plugin_executable.path, out_dir)
37 args = ctx.actions.args()
38 args.add_all(["compile", "--verbose", js_out])
39 args.add_all(["-I" + inc for inc in includes])
40 args.add_all(["-I", system_include])
41 if src_prefix != "":
42 args.add_all(["--src-prefix", src_prefix])
43 
44 args.add_all([s for s in ctx.files.srcs])
45 
46 ctx.actions.run(
47 inputs = inputs + plugin_files + ctx.files._capnpc_capnp + ctx.files._capnp_system,
48 tools = [plugin_executable], # Include required js_binary runfiles
49 outputs = outputs,
50 executable = ctx.executable._capnpc,
51 arguments = [args],
52 mnemonic = "GenCapnp",
53 )
54 
55def _capnp_gen_impl(ctx):
56 label = ctx.label
57 src_prefix = _workspace_path(label, ctx.attr.src_prefix)
58 includes = []
59 
60 inputs = ctx.files.srcs + ctx.files.data
61 for dep_target in ctx.attr.deps:
62 includes += dep_target[capnp_provider].includes
63 inputs += dep_target[capnp_provider].inputs
64 
65 if src_prefix != "":
66 includes.append(src_prefix)
67 
68 system_include = ctx.files._capnp_system[0].dirname.removesuffix("/capnp")
69 
70 out_dir = ctx.var["GENDIR"]
71 if src_prefix != "":
72 out_dir = out_dir + "/" + src_prefix
73 
74 _capnp_plugin_gen(
75 ctx,
76 output_format = "js",
77 out_dir = out_dir,
78 inputs = inputs,
79 includes = includes,
80 src_prefix = src_prefix,
81 system_include = system_include,
82 )
83 
84 _capnp_plugin_gen(
85 ctx,
86 output_format = "ts",
87 out_dir = out_dir,
88 inputs = inputs,
89 includes = includes,
90 src_prefix = src_prefix,
91 system_include = system_include,
92 )
93 
94 return [
95 capnp_provider(
96 includes = includes,
97 inputs = inputs,
98 src_prefix = src_prefix,
99 ),
100 ]
101 
102_capnp_gen = rule(
103 attrs = {
104 "srcs": attr.label_list(allow_files = True),
105 "deps": attr.label_list(providers = [capnp_provider]),
106 "data": attr.label_list(allow_files = True),
107 "outs": attr.output_list(),
108 "src_prefix": attr.string(),
109 "_capnpc": attr.label(executable = True, allow_single_file = True, cfg = "exec", default = "@capnp-cpp//src/capnp:capnp_tool"),
110 "_js_plugin": attr.label(executable = True, allow_single_file = True, cfg = "exec", default = "//:capnpc_js_plugin"),
111 "_ts_plugin": attr.label(executable = True, allow_single_file = True, cfg = "exec", default = "//:capnpc_ts_plugin"),
112 "_capnpc_capnp": attr.label(executable = True, allow_single_file = True, cfg = "exec", default = "@capnp-cpp//src/capnp:capnpc-capnp"),
113 "_capnp_system": attr.label(default = "@capnp-cpp//src/capnp:capnp_system_library"),
114 },
115 output_to_genfiles = True,
116 implementation = _capnp_gen_impl,
117)
118 
119def js_capnp_library(
120 name,
121 srcs = [],
122 data = [],
123 outs = [],
124 deps = [],
125 src_prefix = "",
126 visibility = None,
127 target_compatible_with = None,
128 **kwargs):
129 """Bazel rule to create a JavaScript capnproto library from capnp source files
130 
131 Args:
132 name: library name
133 srcs: list of files to compile
134 data: additional files to provide to the compiler - data files and includes that need not to
135 be compiled
136 outs: expected output files - .js and .ts files
137 deps: other js_capnp_library rules to depend on
138 src_prefix: src_prefix for capnp compiler to the source root
139 visibility: rule visibility
140 target_compatible_with: target compatibility
141 **kwargs: rest of the arguments to js_library rule
142 """
143 
144 _capnp_gen(
145 name = name + "_gen",
146 srcs = srcs,
147 deps = [s + "_gen" for s in deps],
148 data = data,
149 outs = outs,
150 src_prefix = src_prefix,
151 visibility = visibility,
152 target_compatible_with = target_compatible_with,
153 )
154 js_library(
155 name = name,
156 srcs = outs,
157 deps = deps + ["//:node_modules/capnp-es"],
158 visibility = visibility,
159 target_compatible_with = target_compatible_with,
160 **kwargs
161 )