diff third_party/emsdk/bazel/emscripten_toolchain/wasm_cc_binary.bzl @ 186:8cf4ec5e2191 hg-web

Fixed merge conflict.
author MrJuneJune <me@mrjunejune.com>
date Fri, 23 Jan 2026 22:38:59 -0800
parents 8d17f6e6e290
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	Fri Jan 23 22:38:59 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)