Mercurial
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/third_party/emsdk/bazel/emscripten_toolchain/wasm_cc_binary.bzl Thu Jan 22 21:23:17 2026 -0800 @@ -0,0 +1,219 @@ +"""wasm_cc_binary rule for compiling C++ targets to WebAssembly. +""" + +def _wasm_transition_impl(settings, attr): + _ignore = (settings, attr) + + features = list(settings["//command_line_option:features"]) + linkopts = list(settings["//command_line_option:linkopt"]) + + if attr.threads == "emscripten": + # threads enabled + features.append("use_pthreads") + elif attr.threads == "off": + # threads disabled + features.append("-use_pthreads") + + if attr.exit_runtime == True: + features.append("exit_runtime") + + if attr.backend == "llvm": + features.append("llvm_backend") + elif attr.backend == "emscripten": + features.append("-llvm_backend") + + if attr.simd: + features.append("wasm_simd") + + platform = "@emsdk//:platform_wasm" + if attr.standalone: + platform = "@emsdk//:platform_wasi" + features.append("wasm_standalone") + + return { + "//command_line_option:compiler": "emscripten", + "//command_line_option:cpu": "wasm", + "//command_line_option:features": features, + "//command_line_option:dynamic_mode": "off", + "//command_line_option:linkopt": linkopts, + "//command_line_option:platforms": [platform], + # This is hardcoded to an empty cc_library because the malloc library + # is implicitly added by the emscripten toolchain + "//command_line_option:custom_malloc": "@emsdk//emscripten_toolchain:malloc", + } + +_wasm_transition = transition( + implementation = _wasm_transition_impl, + inputs = [ + "//command_line_option:features", + "//command_line_option:linkopt", + ], + outputs = [ + "//command_line_option:compiler", + "//command_line_option:cpu", + "//command_line_option:features", + "//command_line_option:dynamic_mode", + "//command_line_option:linkopt", + "//command_line_option:platforms", + "//command_line_option:custom_malloc", + ], +) + +_ALLOW_OUTPUT_EXTNAMES = [ + ".js", + ".wasm", + ".wasm.map", + ".data", + ".js.symbols", + ".wasm.debug.wasm", + ".html", +] + +_WASM_BINARY_COMMON_ATTRS = { + "backend": attr.string( + default = "_default", + values = ["_default", "emscripten", "llvm"], + ), + "cc_target": attr.label( + cfg = _wasm_transition, + mandatory = True, + ), + "exit_runtime": attr.bool( + default = False, + ), + "threads": attr.string( + default = "_default", + values = ["_default", "emscripten", "off"], + ), + "simd": attr.bool( + default = False, + ), + "standalone": attr.bool( + default = False, + ), + "_allowlist_function_transition": attr.label( + default = "@bazel_tools//tools/allowlists/function_transition_allowlist", + ), + "_wasm_binary_extractor": attr.label( + executable = True, + allow_files = True, + cfg = "exec", + default = Label("@emsdk//emscripten_toolchain:wasm_binary"), + ), +} + +def _wasm_cc_binary_impl(ctx): + args = ctx.actions.args() + cc_target = ctx.attr.cc_target[0] + + for output in ctx.outputs.outputs: + valid_extname = False + for allowed_extname in _ALLOW_OUTPUT_EXTNAMES: + if output.path.endswith(allowed_extname): + valid_extname = True + break + if not valid_extname: + fail("Invalid output '{}'. Allowed extnames: {}".format(output.basename, ", ".join(_ALLOW_OUTPUT_EXTNAMES))) + + args.add_all("--archive", ctx.files.cc_target) + args.add_joined("--outputs", ctx.outputs.outputs, join_with = ",") + + ctx.actions.run( + inputs = ctx.files.cc_target, + outputs = ctx.outputs.outputs, + arguments = [args], + executable = ctx.executable._wasm_binary_extractor, + ) + + return [ + DefaultInfo( + files = depset(ctx.outputs.outputs), + # This is needed since rules like web_test usually have a data + # dependency on this target. + data_runfiles = ctx.runfiles(transitive_files = depset(ctx.outputs.outputs)), + ), + OutputGroupInfo(_wasm_tar = cc_target.files), + ] + +def _wasm_cc_binary_legacy_impl(ctx): + cc_target = ctx.attr.cc_target[0] + outputs = [ + ctx.outputs.loader, + ctx.outputs.wasm, + ctx.outputs.map, + ctx.outputs.data, + ctx.outputs.symbols, + ctx.outputs.dwarf, + ctx.outputs.html, + ] + + args = ctx.actions.args() + args.add("--allow_empty_outputs") + args.add_all("--archive", ctx.files.cc_target) + args.add_joined("--outputs", outputs, join_with = ",") + + ctx.actions.run( + inputs = ctx.files.cc_target, + outputs = outputs, + arguments = [args], + executable = ctx.executable._wasm_binary_extractor, + ) + + return [ + DefaultInfo( + executable = ctx.outputs.wasm, + files = depset(outputs), + # This is needed since rules like web_test usually have a data + # dependency on this target. + data_runfiles = ctx.runfiles(transitive_files = depset(outputs)), + ), + OutputGroupInfo(_wasm_tar = cc_target.files), + ] + +_wasm_cc_binary = rule( + implementation = _wasm_cc_binary_impl, + attrs = dict( + _WASM_BINARY_COMMON_ATTRS, + outputs = attr.output_list( + allow_empty = False, + mandatory = True, + ), + ), +) + +def _wasm_binary_legacy_outputs(name, cc_target): + basename = cc_target.name + basename = basename.split(".")[0] + outputs = { + "loader": "{}/{}.js".format(name, basename), + "wasm": "{}/{}.wasm".format(name, basename), + "map": "{}/{}.wasm.map".format(name, basename), + "data": "{}/{}.data".format(name, basename), + "symbols": "{}/{}.js.symbols".format(name, basename), + "dwarf": "{}/{}.wasm.debug.wasm".format(name, basename), + "html": "{}/{}.html".format(name, basename), + } + + return outputs + +_wasm_cc_binary_legacy = rule( + implementation = _wasm_cc_binary_legacy_impl, + attrs = _WASM_BINARY_COMMON_ATTRS, + outputs = _wasm_binary_legacy_outputs, +) + +# Wraps a C++ Blaze target, extracting the appropriate files. +# +# This rule will transition to the emscripten toolchain in order +# to build the the cc_target as a WebAssembly binary. +# +# Args: +# name: The name of the rule. +# cc_target: The cc_binary or cc_library to extract files from. +def wasm_cc_binary(outputs = None, **kwargs): + # for backwards compatibility if no outputs are set the deprecated + # implementation is used. + if not outputs: + _wasm_cc_binary_legacy(**kwargs) + else: + _wasm_cc_binary(outputs = outputs, **kwargs)