comparison third_party/emsdk/bazel/emscripten_toolchain/wasm_cc_binary.bzl @ 179:8d17f6e6e290

[ThirdParty] Added emsdk bazel rules that can be supported by bazel 9.0.0
author MrJuneJune <me@mrjunejune.com>
date Thu, 22 Jan 2026 21:23:17 -0800
parents
children
comparison
equal deleted inserted replaced
178:94705b5986b3 179:8d17f6e6e290
1 """wasm_cc_binary rule for compiling C++ targets to WebAssembly.
2 """
3
4 def _wasm_transition_impl(settings, attr):
5 _ignore = (settings, attr)
6
7 features = list(settings["//command_line_option:features"])
8 linkopts = list(settings["//command_line_option:linkopt"])
9
10 if attr.threads == "emscripten":
11 # threads enabled
12 features.append("use_pthreads")
13 elif attr.threads == "off":
14 # threads disabled
15 features.append("-use_pthreads")
16
17 if attr.exit_runtime == True:
18 features.append("exit_runtime")
19
20 if attr.backend == "llvm":
21 features.append("llvm_backend")
22 elif attr.backend == "emscripten":
23 features.append("-llvm_backend")
24
25 if attr.simd:
26 features.append("wasm_simd")
27
28 platform = "@emsdk//:platform_wasm"
29 if attr.standalone:
30 platform = "@emsdk//:platform_wasi"
31 features.append("wasm_standalone")
32
33 return {
34 "//command_line_option:compiler": "emscripten",
35 "//command_line_option:cpu": "wasm",
36 "//command_line_option:features": features,
37 "//command_line_option:dynamic_mode": "off",
38 "//command_line_option:linkopt": linkopts,
39 "//command_line_option:platforms": [platform],
40 # This is hardcoded to an empty cc_library because the malloc library
41 # is implicitly added by the emscripten toolchain
42 "//command_line_option:custom_malloc": "@emsdk//emscripten_toolchain:malloc",
43 }
44
45 _wasm_transition = transition(
46 implementation = _wasm_transition_impl,
47 inputs = [
48 "//command_line_option:features",
49 "//command_line_option:linkopt",
50 ],
51 outputs = [
52 "//command_line_option:compiler",
53 "//command_line_option:cpu",
54 "//command_line_option:features",
55 "//command_line_option:dynamic_mode",
56 "//command_line_option:linkopt",
57 "//command_line_option:platforms",
58 "//command_line_option:custom_malloc",
59 ],
60 )
61
62 _ALLOW_OUTPUT_EXTNAMES = [
63 ".js",
64 ".wasm",
65 ".wasm.map",
66 ".data",
67 ".js.symbols",
68 ".wasm.debug.wasm",
69 ".html",
70 ]
71
72 _WASM_BINARY_COMMON_ATTRS = {
73 "backend": attr.string(
74 default = "_default",
75 values = ["_default", "emscripten", "llvm"],
76 ),
77 "cc_target": attr.label(
78 cfg = _wasm_transition,
79 mandatory = True,
80 ),
81 "exit_runtime": attr.bool(
82 default = False,
83 ),
84 "threads": attr.string(
85 default = "_default",
86 values = ["_default", "emscripten", "off"],
87 ),
88 "simd": attr.bool(
89 default = False,
90 ),
91 "standalone": attr.bool(
92 default = False,
93 ),
94 "_allowlist_function_transition": attr.label(
95 default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
96 ),
97 "_wasm_binary_extractor": attr.label(
98 executable = True,
99 allow_files = True,
100 cfg = "exec",
101 default = Label("@emsdk//emscripten_toolchain:wasm_binary"),
102 ),
103 }
104
105 def _wasm_cc_binary_impl(ctx):
106 args = ctx.actions.args()
107 cc_target = ctx.attr.cc_target[0]
108
109 for output in ctx.outputs.outputs:
110 valid_extname = False
111 for allowed_extname in _ALLOW_OUTPUT_EXTNAMES:
112 if output.path.endswith(allowed_extname):
113 valid_extname = True
114 break
115 if not valid_extname:
116 fail("Invalid output '{}'. Allowed extnames: {}".format(output.basename, ", ".join(_ALLOW_OUTPUT_EXTNAMES)))
117
118 args.add_all("--archive", ctx.files.cc_target)
119 args.add_joined("--outputs", ctx.outputs.outputs, join_with = ",")
120
121 ctx.actions.run(
122 inputs = ctx.files.cc_target,
123 outputs = ctx.outputs.outputs,
124 arguments = [args],
125 executable = ctx.executable._wasm_binary_extractor,
126 )
127
128 return [
129 DefaultInfo(
130 files = depset(ctx.outputs.outputs),
131 # This is needed since rules like web_test usually have a data
132 # dependency on this target.
133 data_runfiles = ctx.runfiles(transitive_files = depset(ctx.outputs.outputs)),
134 ),
135 OutputGroupInfo(_wasm_tar = cc_target.files),
136 ]
137
138 def _wasm_cc_binary_legacy_impl(ctx):
139 cc_target = ctx.attr.cc_target[0]
140 outputs = [
141 ctx.outputs.loader,
142 ctx.outputs.wasm,
143 ctx.outputs.map,
144 ctx.outputs.data,
145 ctx.outputs.symbols,
146 ctx.outputs.dwarf,
147 ctx.outputs.html,
148 ]
149
150 args = ctx.actions.args()
151 args.add("--allow_empty_outputs")
152 args.add_all("--archive", ctx.files.cc_target)
153 args.add_joined("--outputs", outputs, join_with = ",")
154
155 ctx.actions.run(
156 inputs = ctx.files.cc_target,
157 outputs = outputs,
158 arguments = [args],
159 executable = ctx.executable._wasm_binary_extractor,
160 )
161
162 return [
163 DefaultInfo(
164 executable = ctx.outputs.wasm,
165 files = depset(outputs),
166 # This is needed since rules like web_test usually have a data
167 # dependency on this target.
168 data_runfiles = ctx.runfiles(transitive_files = depset(outputs)),
169 ),
170 OutputGroupInfo(_wasm_tar = cc_target.files),
171 ]
172
173 _wasm_cc_binary = rule(
174 implementation = _wasm_cc_binary_impl,
175 attrs = dict(
176 _WASM_BINARY_COMMON_ATTRS,
177 outputs = attr.output_list(
178 allow_empty = False,
179 mandatory = True,
180 ),
181 ),
182 )
183
184 def _wasm_binary_legacy_outputs(name, cc_target):
185 basename = cc_target.name
186 basename = basename.split(".")[0]
187 outputs = {
188 "loader": "{}/{}.js".format(name, basename),
189 "wasm": "{}/{}.wasm".format(name, basename),
190 "map": "{}/{}.wasm.map".format(name, basename),
191 "data": "{}/{}.data".format(name, basename),
192 "symbols": "{}/{}.js.symbols".format(name, basename),
193 "dwarf": "{}/{}.wasm.debug.wasm".format(name, basename),
194 "html": "{}/{}.html".format(name, basename),
195 }
196
197 return outputs
198
199 _wasm_cc_binary_legacy = rule(
200 implementation = _wasm_cc_binary_legacy_impl,
201 attrs = _WASM_BINARY_COMMON_ATTRS,
202 outputs = _wasm_binary_legacy_outputs,
203 )
204
205 # Wraps a C++ Blaze target, extracting the appropriate files.
206 #
207 # This rule will transition to the emscripten toolchain in order
208 # to build the the cc_target as a WebAssembly binary.
209 #
210 # Args:
211 # name: The name of the rule.
212 # cc_target: The cc_binary or cc_library to extract files from.
213 def wasm_cc_binary(outputs = None, **kwargs):
214 # for backwards compatibility if no outputs are set the deprecated
215 # implementation is used.
216 if not outputs:
217 _wasm_cc_binary_legacy(**kwargs)
218 else:
219 _wasm_cc_binary(outputs = outputs, **kwargs)