1"""Bazel rules for [wasm-bindgen](https://crates.io/crates/wasm-bindgen)""" 2 3load("//rust:defs.bzl", "rust_common") 4load("//wasm_bindgen:providers.bzl", "RustWasmBindgenInfo") 5load("//wasm_bindgen/private:transitions.bzl", "wasm_bindgen_transition") 6 7def rust_wasm_bindgen_action(ctx, toolchain, wasm_file, target_output, bindgen_flags = []): 8 """Spawn a `RustWasmBindgen` action. 9 10 Args: 11 ctx (ctx): _description_ 12 toolchain (ToolchainInfo): _description_ 13 wasm_file (Target): _description_ 14 target_output (str): _description_ 15 bindgen_flags (list, optional): _description_. Defaults to []. 16 17 Returns: 18 RustWasmBindgenInfo: _description_ 19 """ 20 bindgen_bin = toolchain.bindgen 21 22 # Since the `wasm_file` attribute is behind a transition, it will be converted 23 # to a list. 24 if len(wasm_file) == 1: 25 if rust_common.crate_info in wasm_file[0]: 26 target = wasm_file[0] 27 crate_info = target[rust_common.crate_info] 28 29 # Provide a helpful warning informing users how to use the rule 30 if rust_common.crate_info in target: 31 supported_types = ["cdylib", "bin"] 32 if crate_info.type not in supported_types: 33 fail("The target '{}' is not a supported type: {}".format( 34 ctx.attr.crate.label, 35 supported_types, 36 )) 37 38 progress_message_label = target.label 39 input_file = crate_info.output 40 else: 41 wasm_files = wasm_file[0][DefaultInfo].files.to_list() 42 if len(wasm_files) != 1: 43 fail("Unexpected number of wasm files: {}".format(wasm_files)) 44 45 progress_message_label = wasm_files[0].path 46 input_file = wasm_files[0] 47 else: 48 fail("wasm_file is expected to be a transitioned label attr on `{}`. Got `{}`".format( 49 ctx.label, 50 wasm_file, 51 )) 52 53 bindgen_wasm_module = ctx.actions.declare_file(ctx.label.name + "_bg.wasm") 54 55 js_out = [ctx.actions.declare_file(ctx.label.name + ".js")] 56 ts_out = [ctx.actions.declare_file(ctx.label.name + ".d.ts")] 57 58 if target_output == "bundler": 59 js_out.append(ctx.actions.declare_file(ctx.label.name + "_bg.js")) 60 ts_out.append(ctx.actions.declare_file(ctx.label.name + "_bg.wasm.d.ts")) 61 62 outputs = [bindgen_wasm_module] + js_out + ts_out 63 64 args = ctx.actions.args() 65 args.add("--target", target_output) 66 args.add("--out-dir", bindgen_wasm_module.dirname) 67 args.add("--out-name", ctx.label.name) 68 args.add_all(bindgen_flags) 69 args.add(input_file) 70 71 ctx.actions.run( 72 executable = bindgen_bin, 73 inputs = [input_file], 74 outputs = outputs, 75 mnemonic = "RustWasmBindgen", 76 progress_message = "Generating WebAssembly bindings for {}...".format(progress_message_label), 77 arguments = [args], 78 ) 79 80 return RustWasmBindgenInfo( 81 wasm = bindgen_wasm_module, 82 js = depset(js_out), 83 ts = depset(ts_out), 84 ) 85 86def _rust_wasm_bindgen_impl(ctx): 87 toolchain = ctx.toolchains[Label("//wasm_bindgen:toolchain_type")] 88 89 info = rust_wasm_bindgen_action( 90 ctx = ctx, 91 toolchain = toolchain, 92 wasm_file = ctx.attr.wasm_file, 93 target_output = ctx.attr.target, 94 bindgen_flags = ctx.attr.bindgen_flags, 95 ) 96 97 return [ 98 DefaultInfo( 99 files = depset([info.wasm], transitive = [info.js, info.ts]), 100 ), 101 info, 102 ] 103 104WASM_BINDGEN_ATTR = { 105 "bindgen_flags": attr.string_list( 106 doc = "Flags to pass directly to the bindgen executable. See https://github.com/rustwasm/wasm-bindgen/ for details.", 107 ), 108 "target": attr.string( 109 doc = "The type of output to generate. See https://rustwasm.github.io/wasm-bindgen/reference/deployment.html for details.", 110 default = "bundler", 111 values = ["web", "bundler", "nodejs", "no-modules", "deno"], 112 ), 113 "wasm_file": attr.label( 114 doc = "The `.wasm` file or crate to generate bindings for.", 115 allow_single_file = True, 116 cfg = wasm_bindgen_transition, 117 mandatory = True, 118 ), 119 "_allowlist_function_transition": attr.label( 120 default = Label("//tools/allowlists/function_transition_allowlist"), 121 ), 122} 123 124rust_wasm_bindgen = rule( 125 implementation = _rust_wasm_bindgen_impl, 126 doc = """\ 127Generates javascript and typescript bindings for a webassembly module using [wasm-bindgen][ws]. 128 129[ws]: https://rustwasm.github.io/docs/wasm-bindgen/ 130 131An example of this rule in use can be seen at [@rules_rust//examples/wasm](../examples/wasm) 132""", 133 attrs = { 134 "bindgen_flags": attr.string_list( 135 doc = "Flags to pass directly to the bindgen executable. See https://github.com/rustwasm/wasm-bindgen/ for details.", 136 ), 137 "target": attr.string( 138 doc = "The type of output to generate. See https://rustwasm.github.io/wasm-bindgen/reference/deployment.html for details.", 139 default = "bundler", 140 values = ["web", "bundler", "nodejs", "no-modules", "deno"], 141 ), 142 "wasm_file": attr.label( 143 doc = "The `.wasm` file or crate to generate bindings for.", 144 allow_single_file = True, 145 cfg = wasm_bindgen_transition, 146 mandatory = True, 147 ), 148 "_allowlist_function_transition": attr.label( 149 default = Label("//tools/allowlists/function_transition_allowlist"), 150 ), 151 }, 152 toolchains = [ 153 str(Label("//wasm_bindgen:toolchain_type")), 154 ], 155) 156 157def _rust_wasm_bindgen_toolchain_impl(ctx): 158 return platform_common.ToolchainInfo( 159 bindgen = ctx.executable.bindgen, 160 ) 161 162rust_wasm_bindgen_toolchain = rule( 163 implementation = _rust_wasm_bindgen_toolchain_impl, 164 doc = """\ 165The tools required for the `rust_wasm_bindgen` rule. 166 167In cases where users want to control or change the version of `wasm-bindgen` used by [rust_wasm_bindgen](#rust_wasm_bindgen), 168a unique toolchain can be created as in the example below: 169 170```python 171load("@rules_rust//bindgen:bindgen.bzl", "rust_bindgen_toolchain") 172 173rust_bindgen_toolchain( 174 bindgen = "//3rdparty/crates:wasm_bindgen_cli__bin", 175) 176 177toolchain( 178 name = "wasm_bindgen_toolchain", 179 toolchain = "wasm_bindgen_toolchain_impl", 180 toolchain_type = "@rules_rust//wasm_bindgen:toolchain_type", 181) 182``` 183 184Now that you have your own toolchain, you need to register it by 185inserting the following statement in your `WORKSPACE` file: 186 187```python 188register_toolchains("//my/toolchains:wasm_bindgen_toolchain") 189``` 190 191For additional information, see the [Bazel toolchains documentation][toolchains]. 192 193[toolchains]: https://docs.bazel.build/versions/master/toolchains.html 194""", 195 attrs = { 196 "bindgen": attr.label( 197 doc = "The label of a `wasm-bindgen-cli` executable.", 198 executable = True, 199 cfg = "exec", 200 ), 201 }, 202) 203