Added support for multiple javascript rule sets to wasm_bindgen package (#2284)

This PR converts the core `rust_wasm_bindgen` rule into a standalone
rule that users can user to write custom interfaces into any
rules/targets they desire while also supporting interfaces for existing
Javascript rule sets. Users loading the root `@rules_rust//wasm_bindgen`
symbols will be using the core Rust rules, where users loading symbols
from the new sub directories `rules_nodejs` and `rules_js` will have
variants that offer better integrations.
This commit is contained in:
UebelAndre 2023-11-27 06:20:45 -08:00 committed by GitHub
parent b96e37ecf4
commit 76daee3047
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 692 additions and 302 deletions

View File

@ -412,8 +412,6 @@ tasks:
- "//..."
# The proto rules do not work on windows
- "-//proto/..."
# The wasm rules do not work on windows
- "-//wasm/..."
# The bindgen rules are currently broken on windows
# https://github.com/bazelbuild/rules_rust/issues/2009
- "-//bindgen/..."

View File

@ -10,7 +10,7 @@ on:
- synchronize
jobs:
clang-format-checking:
code-format-checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
@ -19,3 +19,13 @@ jobs:
source: '.'
extensions: 'h,c,cc,proto'
clangFormatVersion: 14
- uses: actionsx/prettier@v2
with:
args: --config "${{ github.workspace }}/.prettierrc.toml" --write "**/*.{js,ts}"
# Prettier has no diff view so we must make one ourselves
# https://github.com/prettier/prettier/issues/6885
- run: |
git diff
if [[ -n "$(git status --porcelain)" ]]; then
exit 1
fi

3
.prettierrc.toml Normal file
View File

@ -0,0 +1,3 @@
# Prettier config file. For more opitons see https://prettier.io/docs/en/options
tabWidth = 4
trailingComma = "all"

View File

@ -9,7 +9,6 @@ bzl_library(
srcs = [
"@bazel_tools//tools:bzl_srcs",
"@com_google_protobuf//:bzl_srcs",
"@rules_nodejs//nodejs:bzl",
],
deps = [
"@bazel_skylib//lib:paths",
@ -152,6 +151,7 @@ PAGES = dict([
"rust_wasm_bindgen_register_toolchains",
"rust_wasm_bindgen_toolchain",
"rust_wasm_bindgen",
"RustWasmBindgenInfo",
],
),
page(

View File

@ -2,6 +2,7 @@
* [CrateInfo](#CrateInfo)
* [DepInfo](#DepInfo)
* [RustWasmBindgenInfo](#RustWasmBindgenInfo)
* [StdLibInfo](#StdLibInfo)
* [capture_clippy_output](#capture_clippy_output)
* [cargo_bootstrap_repository](#cargo_bootstrap_repository)
@ -1330,17 +1331,6 @@ Generates javascript and typescript bindings for a webassembly module using [was
[ws]: https://rustwasm.github.io/docs/wasm-bindgen/
To use the Rust WebAssembly bindgen rules, add the following to your `WORKSPACE` file to add the
external repositories for the Rust bindgen toolchain (in addition to the Rust rules setup):
```python
load("@rules_rust//wasm_bindgen:repositories.bzl", "rust_wasm_bindgen_repositories")
rust_wasm_bindgen_repositories()
```
For more details on `rust_wasm_bindgen_repositories`, see [here](#rust_wasm_bindgen_repositories).
An example of this rule in use can be seen at [@rules_rust//examples/wasm](../examples/wasm)
@ -1509,6 +1499,26 @@ A provider containing information about a Crate's dependencies.
| <a id="DepInfo-transitive_proc_macro_data"></a>transitive_proc_macro_data | depset[File]: Data of all transitive proc-macro dependencies, and non-macro dependencies of those macros. |
<a id="RustWasmBindgenInfo"></a>
## RustWasmBindgenInfo
<pre>
RustWasmBindgenInfo(<a href="#RustWasmBindgenInfo-js">js</a>, <a href="#RustWasmBindgenInfo-ts">ts</a>, <a href="#RustWasmBindgenInfo-wasm">wasm</a>)
</pre>
Info about wasm-bindgen outputs.
**FIELDS**
| Name | Description |
| :------------- | :------------- |
| <a id="RustWasmBindgenInfo-js"></a>js | Depset[File]: The Javascript files produced by <code>wasm-bindgen</code>. |
| <a id="RustWasmBindgenInfo-ts"></a>ts | Depset[File]: The Typescript files produced by <code>wasm-bindgen</code>. |
| <a id="RustWasmBindgenInfo-wasm"></a>wasm | File: The <code>.wasm</code> file generated by <code>wasm-bindgen</code>. |
<a id="StdLibInfo"></a>
## StdLibInfo

View File

@ -5,24 +5,45 @@
* [rust_wasm_bindgen_register_toolchains](#rust_wasm_bindgen_register_toolchains)
* [rust_wasm_bindgen_toolchain](#rust_wasm_bindgen_toolchain)
* [rust_wasm_bindgen](#rust_wasm_bindgen)
* [RustWasmBindgenInfo](#RustWasmBindgenInfo)
## Overview
To build a `rust_binary` for `wasm32-unknown-unknown` target add the `--platforms=@rules_rust//rust/platform:wasm` flag.
Bazel rules for generating wasm modules for Javascript using [wasm-bindgen][wb].
```command
bazel build @examples//hello_world_wasm --platforms=@rules_rust//rust/platform:wasm
## Setup
To begin using the `wasm-bindgen` rules, users can load the necessary dependencies
in their workspace by adding the following to their `WORKSPACE.bazel` file.
```starlark
load("@rules_rust//wasm_bindgen:repositories.bzl", "rust_wasm_bindgen_dependencies", "rust_wasm_bindgen_register_toolchains")
rust_wasm_bindgen_dependencies()
rust_wasm_bindgen_register_toolchains()
```
To build a `rust_binary` for `wasm32-wasi` target add the `--platforms=@rules_rust//rust/platform:wasi` flag.
This should enable users to start using the [rust_wasm_bindgen](#rust_wasm_bindgen)
rule. However, it's common to want to control the version of `wasm-bindgen` in the
workspace instead of relying on the one provided by `rules_rust`. In this case, users
should avoid calling `rust_wasm_bindgen_register_toolchains` and instead use the
[rust_wasm_bindgen_toolchain](#rust_wasm_bindgen_toolchain) rule to define their own
toolchains to register in the workspace.
```command
bazel build @examples//hello_world_wasm --platforms=@rules_rust//rust/platform:wasi
```
### Interfacing with Javascript rules
`rust_wasm_bindgen` will automatically transition to the `wasm` platform and can be used when
building WebAssembly code for the host target.
While it's recommended for users to mantain their own , in the
`@rules_rust//wasm_bindgen` package there exists interface sub-packages for various
Javascript Bazel rules. E.g. `build_bazel_rules_nodejs` or `aspect_rules_js`. The
rules defined there are a more convenient way to use `rust_wasm_bindgen` with the
associated javascript rules due to the inclusion of additional providers. Each
directory contains a `defs.bzl` file that defines the different variants of
`rust_wasm_bindgen`. (e.g. `nodejs_rust_wasm_bindgen` for the `rules_nodejs` submodule).
[wb]: https://github.com/rustwasm/wasm-bindgen
<a id="rust_wasm_bindgen"></a>
@ -37,17 +58,6 @@ Generates javascript and typescript bindings for a webassembly module using [was
[ws]: https://rustwasm.github.io/docs/wasm-bindgen/
To use the Rust WebAssembly bindgen rules, add the following to your `WORKSPACE` file to add the
external repositories for the Rust bindgen toolchain (in addition to the Rust rules setup):
```python
load("@rules_rust//wasm_bindgen:repositories.bzl", "rust_wasm_bindgen_repositories")
rust_wasm_bindgen_repositories()
```
For more details on `rust_wasm_bindgen_repositories`, see [here](#rust_wasm_bindgen_repositories).
An example of this rule in use can be seen at [@rules_rust//examples/wasm](../examples/wasm)
@ -110,6 +120,26 @@ For additional information, see the [Bazel toolchains documentation][toolchains]
| <a id="rust_wasm_bindgen_toolchain-bindgen"></a>bindgen | The label of a <code>wasm-bindgen-cli</code> executable. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
<a id="RustWasmBindgenInfo"></a>
## RustWasmBindgenInfo
<pre>
RustWasmBindgenInfo(<a href="#RustWasmBindgenInfo-js">js</a>, <a href="#RustWasmBindgenInfo-ts">ts</a>, <a href="#RustWasmBindgenInfo-wasm">wasm</a>)
</pre>
Info about wasm-bindgen outputs.
**FIELDS**
| Name | Description |
| :------------- | :------------- |
| <a id="RustWasmBindgenInfo-js"></a>js | Depset[File]: The Javascript files produced by <code>wasm-bindgen</code>. |
| <a id="RustWasmBindgenInfo-ts"></a>ts | Depset[File]: The Typescript files produced by <code>wasm-bindgen</code>. |
| <a id="RustWasmBindgenInfo-wasm"></a>wasm | File: The <code>.wasm</code> file generated by <code>wasm-bindgen</code>. |
<a id="rust_wasm_bindgen_dependencies"></a>
## rust_wasm_bindgen_dependencies

View File

@ -1,18 +1,38 @@
#[[
## Overview
To build a `rust_binary` for `wasm32-unknown-unknown` target add the `--platforms=@rules_rust//rust/platform:wasm` flag.
Bazel rules for generating wasm modules for Javascript using [wasm-bindgen][wb].
```command
bazel build @examples//hello_world_wasm --platforms=@rules_rust//rust/platform:wasm
## Setup
To begin using the `wasm-bindgen` rules, users can load the necessary dependencies
in their workspace by adding the following to their `WORKSPACE.bazel` file.
```starlark
load("@rules_rust//wasm_bindgen:repositories.bzl", "rust_wasm_bindgen_dependencies", "rust_wasm_bindgen_register_toolchains")
rust_wasm_bindgen_dependencies()
rust_wasm_bindgen_register_toolchains()
```
To build a `rust_binary` for `wasm32-wasi` target add the `--platforms=@rules_rust//rust/platform:wasi` flag.
This should enable users to start using the [rust_wasm_bindgen](#rust_wasm_bindgen)
rule. However, it's common to want to control the version of `wasm-bindgen` in the
workspace instead of relying on the one provided by `rules_rust`. In this case, users
should avoid calling `rust_wasm_bindgen_register_toolchains` and instead use the
[rust_wasm_bindgen_toolchain](#rust_wasm_bindgen_toolchain) rule to define their own
toolchains to register in the workspace.
```command
bazel build @examples//hello_world_wasm --platforms=@rules_rust//rust/platform:wasi
```
### Interfacing with Javascript rules
`rust_wasm_bindgen` will automatically transition to the `wasm` platform and can be used when
building WebAssembly code for the host target.
While it's recommended for users to mantain their own , in the
`@rules_rust//wasm_bindgen` package there exists interface sub-packages for various
Javascript Bazel rules. E.g. `build_bazel_rules_nodejs` or `aspect_rules_js`. The
rules defined there are a more convenient way to use `rust_wasm_bindgen` with the
associated javascript rules due to the inclusion of additional providers. Each
directory contains a `defs.bzl` file that defines the different variants of
`rust_wasm_bindgen`. (e.g. `nodejs_rust_wasm_bindgen` for the `rules_nodejs` submodule).
[wb]: https://github.com/rustwasm/wasm-bindgen
]]#

View File

@ -110,16 +110,17 @@ load(
"@rules_rust//rust/settings:incompatible.bzl",
_incompatible_flag = "incompatible_flag",
)
load(
"@rules_rust//wasm_bindgen:defs.bzl",
_RustWasmBindgenInfo = "RustWasmBindgenInfo",
_rust_wasm_bindgen = "rust_wasm_bindgen",
_rust_wasm_bindgen_toolchain = "rust_wasm_bindgen_toolchain",
)
load(
"@rules_rust//wasm_bindgen:repositories.bzl",
_rust_wasm_bindgen_dependencies = "rust_wasm_bindgen_dependencies",
_rust_wasm_bindgen_register_toolchains = "rust_wasm_bindgen_register_toolchains",
)
load(
"@rules_rust//wasm_bindgen:wasm_bindgen.bzl",
_rust_wasm_bindgen = "rust_wasm_bindgen",
_rust_wasm_bindgen_toolchain = "rust_wasm_bindgen_toolchain",
)
rust_binary = _rust_binary
rust_library = _rust_library
@ -161,6 +162,7 @@ rust_wasm_bindgen = _rust_wasm_bindgen
rust_wasm_bindgen_dependencies = _rust_wasm_bindgen_dependencies
rust_wasm_bindgen_register_toolchains = _rust_wasm_bindgen_register_toolchains
rust_wasm_bindgen_toolchain = _rust_wasm_bindgen_toolchain
RustWasmBindgenInfo = _RustWasmBindgenInfo
rules_rust_dependencies = _rules_rust_dependencies
rust_register_toolchains = _rust_register_toolchains

View File

@ -50,6 +50,14 @@ rust_wasm_bindgen_dependencies()
rust_wasm_bindgen_register_toolchains()
load("@rules_rust//wasm_bindgen/rules_nodejs:repositories.bzl", "nodejs_rust_wasm_bindgen_dependencies")
nodejs_rust_wasm_bindgen_dependencies()
load("@rules_rust//wasm_bindgen/rules_js:repositories.bzl", "js_rust_wasm_bindgen_dependencies")
js_rust_wasm_bindgen_dependencies()
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
###############################################################################
@ -81,14 +89,29 @@ rust_repository_set(
http_archive(
name = "build_bazel_rules_nodejs",
sha256 = "c78216f5be5d451a42275b0b7dc809fb9347e2b04a68f68bad620a2b01f5c774",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/5.5.2/rules_nodejs-5.5.2.tar.gz"],
sha256 = "709cc0dcb51cf9028dd57c268066e5bc8f03a119ded410a13b5c3925d6e43c48",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/5.8.4/rules_nodejs-5.8.4.tar.gz"],
)
load("@build_bazel_rules_nodejs//:index.bzl", "node_repositories")
node_repositories()
load("@aspect_rules_js//js:repositories.bzl", "rules_js_dependencies")
rules_js_dependencies()
load("@rules_nodejs//nodejs:repositories.bzl", "DEFAULT_NODE_VERSION", "nodejs_register_toolchains")
nodejs_register_toolchains(
name = "nodejs",
node_version = DEFAULT_NODE_VERSION,
)
load("@bazel_features//:deps.bzl", "bazel_features_deps")
bazel_features_deps()
http_archive(
name = "rules_foreign_cc",
sha256 = "69023642d5781c68911beda769f91fcbc8ca48711db935a75da7f6536b65047f",

View File

@ -1,23 +0,0 @@
"use strict";
const fs = require('fs');
const path = require('path');
const assert = require('assert');
const main = async function (typ) {
const wasm_file = path.join(__dirname, 'hello_world_'+typ+'_wasm_bindgen_bg.wasm');
assert.ok(fs.existsSync(wasm_file));
const buf = fs.readFileSync(wasm_file);
assert.ok(buf);
const res = await WebAssembly.instantiate(buf);
assert.ok(res);
assert.strictEqual(res.instance.exports.double(2), 4);
};
["bundler", "web", "deno", "nomodules", "nodejs"].forEach((typ) => {
main(typ).catch(function (err) {
console.error(err);
process.exit(1);
});
})

View File

@ -12,11 +12,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_test")
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_shared_library")
load("@rules_rust//wasm_bindgen:wasm_bindgen.bzl", "rust_wasm_bindgen")
load("@rules_rust//wasm_bindgen:defs.bzl", "rust_wasm_bindgen")
package(default_visibility = ["//visibility:public"])
package(default_visibility = ["//wasm_bindgen:__subpackages__"])
exports_files([
"hello_world_wasm_test.js",
"main.rs",
])
rust_binary(
name = "hello_world_bin_wasm",
@ -64,15 +68,3 @@ rust_wasm_bindgen(
target = "nodejs",
wasm_file = ":hello_world_lib_wasm",
)
nodejs_test(
name = "hello_world_wasm_test",
data = [
":hello_world_bundler_wasm_bindgen",
":hello_world_deno_wasm_bindgen",
":hello_world_nodejs_wasm_bindgen",
":hello_world_nomodules_wasm_bindgen",
":hello_world_web_wasm_bindgen",
],
entry_point = "hello_world_wasm_test.js",
)

View File

@ -0,0 +1,27 @@
"use strict";
const fs = require("fs");
const path = require("path");
const assert = require("assert");
const main = async function (typ, dir) {
const wasm_file = path.join(
__dirname,
dir,
"hello_world_" + typ + "_wasm_bindgen_bg.wasm",
);
const buf = fs.readFileSync(wasm_file);
assert.ok(buf);
const res = await WebAssembly.instantiate(buf);
assert.ok(res);
assert.strictEqual(res.instance.exports.double(2), 4);
};
["bundler", "web", "deno", "nomodules", "nodejs"].forEach((typ) => {
main(typ, process.argv.length > 2 ? process.argv[2] : "").catch(function (
err,
) {
console.error(err);
process.exit(1);
});
});

View File

@ -0,0 +1,71 @@
load("@aspect_rules_js//js:defs.bzl", "js_test")
load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_shared_library")
load("@rules_rust//wasm_bindgen/rules_js:defs.bzl", "js_rust_wasm_bindgen")
package(default_visibility = ["//visibility:public"])
copy_file(
name = "hello_world_wasm_test.src",
src = "//wasm_bindgen:hello_world_wasm_test.js",
out = "hello_world_wasm_test.js",
)
rust_binary(
name = "hello_world_bin_wasm",
srcs = ["//wasm_bindgen:main.rs"],
edition = "2018",
deps = [
"@rules_rust//wasm_bindgen/3rdparty:wasm_bindgen",
],
)
rust_shared_library(
name = "hello_world_lib_wasm",
srcs = ["//wasm_bindgen:main.rs"],
edition = "2018",
deps = [
"@rules_rust//wasm_bindgen/3rdparty:wasm_bindgen",
],
)
js_rust_wasm_bindgen(
name = "hello_world_bundler_wasm_bindgen",
wasm_file = ":hello_world_bin_wasm",
)
js_rust_wasm_bindgen(
name = "hello_world_web_wasm_bindgen",
target = "web",
wasm_file = ":hello_world_lib_wasm",
)
js_rust_wasm_bindgen(
name = "hello_world_deno_wasm_bindgen",
target = "deno",
wasm_file = ":hello_world_lib_wasm",
)
js_rust_wasm_bindgen(
name = "hello_world_nomodules_wasm_bindgen",
target = "no-modules",
wasm_file = ":hello_world_lib_wasm",
)
js_rust_wasm_bindgen(
name = "hello_world_nodejs_wasm_bindgen",
target = "nodejs",
wasm_file = ":hello_world_lib_wasm",
)
js_test(
name = "hello_world_wasm_test",
data = [
":hello_world_bundler_wasm_bindgen",
":hello_world_deno_wasm_bindgen",
":hello_world_nodejs_wasm_bindgen",
":hello_world_nomodules_wasm_bindgen",
":hello_world_web_wasm_bindgen",
],
entry_point = ":hello_world_wasm_test.js",
)

View File

@ -0,0 +1,65 @@
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_test")
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_shared_library")
load("@rules_rust//wasm_bindgen/rules_nodejs:defs.bzl", "nodejs_rust_wasm_bindgen")
package(default_visibility = ["//visibility:public"])
rust_binary(
name = "hello_world_bin_wasm",
srcs = ["//wasm_bindgen:main.rs"],
edition = "2018",
deps = [
"@rules_rust//wasm_bindgen/3rdparty:wasm_bindgen",
],
)
rust_shared_library(
name = "hello_world_lib_wasm",
srcs = ["//wasm_bindgen:main.rs"],
edition = "2018",
deps = [
"@rules_rust//wasm_bindgen/3rdparty:wasm_bindgen",
],
)
nodejs_rust_wasm_bindgen(
name = "hello_world_bundler_wasm_bindgen",
wasm_file = ":hello_world_bin_wasm",
)
nodejs_rust_wasm_bindgen(
name = "hello_world_web_wasm_bindgen",
target = "web",
wasm_file = ":hello_world_lib_wasm",
)
nodejs_rust_wasm_bindgen(
name = "hello_world_deno_wasm_bindgen",
target = "deno",
wasm_file = ":hello_world_lib_wasm",
)
nodejs_rust_wasm_bindgen(
name = "hello_world_nomodules_wasm_bindgen",
target = "no-modules",
wasm_file = ":hello_world_lib_wasm",
)
nodejs_rust_wasm_bindgen(
name = "hello_world_nodejs_wasm_bindgen",
target = "nodejs",
wasm_file = ":hello_world_lib_wasm",
)
nodejs_test(
name = "hello_world_wasm_test",
args = ["rules_nodejs"],
data = [
":hello_world_bundler_wasm_bindgen",
":hello_world_deno_wasm_bindgen",
":hello_world_nodejs_wasm_bindgen",
":hello_world_nomodules_wasm_bindgen",
":hello_world_web_wasm_bindgen",
],
entry_point = "//wasm_bindgen:hello_world_wasm_test.js",
)

View File

@ -1,5 +1,5 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("//wasm_bindgen:wasm_bindgen.bzl", "rust_wasm_bindgen_toolchain")
load("//wasm_bindgen:defs.bzl", "rust_wasm_bindgen_toolchain")
package(default_visibility = ["//visibility:public"])
@ -7,13 +7,6 @@ toolchain_type(
name = "toolchain_type",
)
alias(
name = "wasm_bindgen_toolchain",
actual = "toolchain_type",
deprecation = "instead use `@rules_rust//wasm_bindgen:toolchain_type`",
tags = ["manual"],
)
bzl_library(
name = "bzl_lib",
srcs = glob(["**/*.bzl"]),

15
wasm_bindgen/defs.bzl Normal file
View File

@ -0,0 +1,15 @@
"""Bazel rules for [wasm-bindgen](https://crates.io/crates/wasm-bindgen)"""
load(
"//wasm_bindgen:providers.bzl",
_RustWasmBindgenInfo = "RustWasmBindgenInfo",
)
load(
"//wasm_bindgen/private:wasm_bindgen.bzl",
_rust_wasm_bindgen = "rust_wasm_bindgen",
_rust_wasm_bindgen_toolchain = "rust_wasm_bindgen_toolchain",
)
rust_wasm_bindgen = _rust_wasm_bindgen
rust_wasm_bindgen_toolchain = _rust_wasm_bindgen_toolchain
RustWasmBindgenInfo = _RustWasmBindgenInfo

View File

@ -4,6 +4,7 @@ bzl_library(
name = "bzl_lib",
srcs = [
"transitions.bzl",
"wasm_bindgen.bzl",
],
visibility = ["//wasm_bindgen:__pkg__"],
)

View File

@ -0,0 +1,203 @@
"""Bazel rules for [wasm-bindgen](https://crates.io/crates/wasm-bindgen)"""
load("//rust:defs.bzl", "rust_common")
load("//wasm_bindgen:providers.bzl", "RustWasmBindgenInfo")
load("//wasm_bindgen/private:transitions.bzl", "wasm_bindgen_transition")
def rust_wasm_bindgen_action(ctx, toolchain, wasm_file, target_output, bindgen_flags = []):
"""Spawn a `RustWasmBindgen` action.
Args:
ctx (ctx): _description_
toolchain (ToolchainInfo): _description_
wasm_file (Target): _description_
target_output (str): _description_
bindgen_flags (list, optional): _description_. Defaults to [].
Returns:
RustWasmBindgenInfo: _description_
"""
bindgen_bin = toolchain.bindgen
# Since the `wasm_file` attribute is behind a transition, it will be converted
# to a list.
if len(wasm_file) == 1:
if rust_common.crate_info in wasm_file[0]:
target = wasm_file[0]
crate_info = target[rust_common.crate_info]
# Provide a helpful warning informing users how to use the rule
if rust_common.crate_info in target:
supported_types = ["cdylib", "bin"]
if crate_info.type not in supported_types:
fail("The target '{}' is not a supported type: {}".format(
ctx.attr.crate.label,
supported_types,
))
progress_message_label = target.label
input_file = crate_info.output
else:
wasm_files = wasm_file[0][DefaultInfo].files.to_list()
if len(wasm_files) != 1:
fail("Unexpected number of wasm files: {}".format(wasm_files))
progress_message_label = wasm_files[0].path
input_file = wasm_files[0]
else:
fail("wasm_file is expected to be a transitioned label attr on `{}`. Got `{}`".format(
ctx.label,
wasm_file,
))
bindgen_wasm_module = ctx.actions.declare_file(ctx.label.name + "_bg.wasm")
js_out = [ctx.actions.declare_file(ctx.label.name + ".js")]
ts_out = [ctx.actions.declare_file(ctx.label.name + ".d.ts")]
if target_output == "bundler":
js_out.append(ctx.actions.declare_file(ctx.label.name + "_bg.js"))
ts_out.append(ctx.actions.declare_file(ctx.label.name + "_bg.wasm.d.ts"))
outputs = [bindgen_wasm_module] + js_out + ts_out
args = ctx.actions.args()
args.add("--target", target_output)
args.add("--out-dir", bindgen_wasm_module.dirname)
args.add("--out-name", ctx.label.name)
args.add_all(bindgen_flags)
args.add(input_file)
ctx.actions.run(
executable = bindgen_bin,
inputs = [input_file],
outputs = outputs,
mnemonic = "RustWasmBindgen",
progress_message = "Generating WebAssembly bindings for {}...".format(progress_message_label),
arguments = [args],
)
return RustWasmBindgenInfo(
wasm = bindgen_wasm_module,
js = depset(js_out),
ts = depset(ts_out),
)
def _rust_wasm_bindgen_impl(ctx):
toolchain = ctx.toolchains[Label("//wasm_bindgen:toolchain_type")]
info = rust_wasm_bindgen_action(
ctx = ctx,
toolchain = toolchain,
wasm_file = ctx.attr.wasm_file,
target_output = ctx.attr.target,
bindgen_flags = ctx.attr.bindgen_flags,
)
return [
DefaultInfo(
files = depset(transitive = [info.js, info.ts]),
),
info,
]
WASM_BINDGEN_ATTR = {
"bindgen_flags": attr.string_list(
doc = "Flags to pass directly to the bindgen executable. See https://github.com/rustwasm/wasm-bindgen/ for details.",
),
"target": attr.string(
doc = "The type of output to generate. See https://rustwasm.github.io/wasm-bindgen/reference/deployment.html for details.",
default = "bundler",
values = ["web", "bundler", "nodejs", "no-modules", "deno"],
),
"wasm_file": attr.label(
doc = "The `.wasm` file or crate to generate bindings for.",
allow_single_file = True,
cfg = wasm_bindgen_transition,
mandatory = True,
),
"_allowlist_function_transition": attr.label(
default = Label("//tools/allowlists/function_transition_allowlist"),
),
}
rust_wasm_bindgen = rule(
implementation = _rust_wasm_bindgen_impl,
doc = """\
Generates javascript and typescript bindings for a webassembly module using [wasm-bindgen][ws].
[ws]: https://rustwasm.github.io/docs/wasm-bindgen/
An example of this rule in use can be seen at [@rules_rust//examples/wasm](../examples/wasm)
""",
attrs = {
"bindgen_flags": attr.string_list(
doc = "Flags to pass directly to the bindgen executable. See https://github.com/rustwasm/wasm-bindgen/ for details.",
),
"target": attr.string(
doc = "The type of output to generate. See https://rustwasm.github.io/wasm-bindgen/reference/deployment.html for details.",
default = "bundler",
values = ["web", "bundler", "nodejs", "no-modules", "deno"],
),
"wasm_file": attr.label(
doc = "The `.wasm` file or crate to generate bindings for.",
allow_single_file = True,
cfg = wasm_bindgen_transition,
mandatory = True,
),
"_allowlist_function_transition": attr.label(
default = Label("//tools/allowlists/function_transition_allowlist"),
),
},
toolchains = [
str(Label("//wasm_bindgen:toolchain_type")),
],
incompatible_use_toolchain_transition = True,
)
def _rust_wasm_bindgen_toolchain_impl(ctx):
return platform_common.ToolchainInfo(
bindgen = ctx.executable.bindgen,
)
rust_wasm_bindgen_toolchain = rule(
implementation = _rust_wasm_bindgen_toolchain_impl,
doc = """\
The tools required for the `rust_wasm_bindgen` rule.
In cases where users want to control or change the version of `wasm-bindgen` used by [rust_wasm_bindgen](#rust_wasm_bindgen),
a unique toolchain can be created as in the example below:
```python
load("@rules_rust//bindgen:bindgen.bzl", "rust_bindgen_toolchain")
rust_bindgen_toolchain(
bindgen = "//3rdparty/crates:wasm_bindgen_cli__bin",
)
toolchain(
name = "wasm_bindgen_toolchain",
toolchain = "wasm_bindgen_toolchain_impl",
toolchain_type = "@rules_rust//wasm_bindgen:toolchain_type",
)
```
Now that you have your own toolchain, you need to register it by
inserting the following statement in your `WORKSPACE` file:
```python
register_toolchains("//my/toolchains:wasm_bindgen_toolchain")
```
For additional information, see the [Bazel toolchains documentation][toolchains].
[toolchains]: https://docs.bazel.build/versions/master/toolchains.html
""",
attrs = {
"bindgen": attr.label(
doc = "The label of a `wasm-bindgen-cli` executable.",
executable = True,
cfg = "exec",
),
},
)

View File

@ -1,10 +1,10 @@
"""A module for re-exporting the providers used by the rust_wasm_bindgen rule"""
"""Rust WASM bindgen providers"""
load(
"@rules_nodejs//nodejs:providers.bzl",
_DeclarationInfo = "DeclarationInfo",
_JSModuleInfo = "JSModuleInfo",
RustWasmBindgenInfo = provider(
doc = "Info about wasm-bindgen outputs.",
fields = {
"js": "Depset[File]: The Javascript files produced by `wasm-bindgen`.",
"ts": "Depset[File]: The Typescript files produced by `wasm-bindgen`.",
"wasm": "File: The `.wasm` file generated by `wasm-bindgen`.",
},
)
DeclarationInfo = _DeclarationInfo
JSModuleInfo = _JSModuleInfo

View File

@ -39,13 +39,6 @@ def rust_wasm_bindgen_dependencies():
patches = [Label("//wasm_bindgen/3rdparty/patches:resolver.patch")],
)
maybe(
http_archive,
name = "rules_nodejs",
sha256 = "017e2348bb8431156d5cf89b6f502c2e7fcffc568729f74f89e4a12bd8279e90",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/5.5.2/rules_nodejs-core-5.5.2.tar.gz"],
)
crate_repositories()
# buildifier: disable=unnamed-macro

View File

@ -0,0 +1 @@
"""Rust WASM-bindgen rules for interfacing with aspects/rules_js"""

View File

@ -0,0 +1,49 @@
"""Rust WASM-bindgen rules for interfacing with aspect-build/rules_js"""
load("@aspect_rules_js//js:providers.bzl", "JsInfo")
load("//wasm_bindgen/private:wasm_bindgen.bzl", "WASM_BINDGEN_ATTR", "rust_wasm_bindgen_action")
def _js_rust_wasm_bindgen_impl(ctx):
toolchain = ctx.toolchains[Label("//wasm_bindgen:toolchain_type")]
info = rust_wasm_bindgen_action(
ctx = ctx,
toolchain = toolchain,
wasm_file = ctx.attr.wasm_file,
target_output = ctx.attr.target,
bindgen_flags = ctx.attr.bindgen_flags,
)
# Return a structure that is compatible with the deps[] of a ts_library.
declarations = info.ts
es5_sources = info.js
return [
DefaultInfo(
files = depset([info.wasm], transitive = [info.js, info.ts]),
),
info,
JsInfo(
declarations = declarations,
sources = es5_sources,
transitive_declarations = declarations,
transitive_sources = es5_sources,
),
]
js_rust_wasm_bindgen = rule(
doc = """\
Generates javascript and typescript bindings for a webassembly module using [wasm-bindgen][ws] that interface with [aspect-build/rules_js][abjs].
[ws]: https://rustwasm.github.io/docs/wasm-bindgen/
[abjs]: https://github.com/aspect-build/rules_js
An example of this rule in use can be seen at [@rules_rust//examples/wasm_bindgen/rules_js](../examples/wasm_bindgen/rules_js)
""",
implementation = _js_rust_wasm_bindgen_impl,
attrs = WASM_BINDGEN_ATTR,
toolchains = [
str(Label("//wasm_bindgen:toolchain_type")),
],
incompatible_use_toolchain_transition = True,
)

View File

@ -0,0 +1,23 @@
"""TODO"""
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
load(
"//wasm_bindgen:repositories.bzl",
_rust_wasm_bindgen_dependencies = "rust_wasm_bindgen_dependencies",
_rust_wasm_bindgen_register_toolchains = "rust_wasm_bindgen_register_toolchains",
)
def js_rust_wasm_bindgen_dependencies():
_rust_wasm_bindgen_dependencies()
maybe(
http_archive,
name = "aspect_rules_js",
sha256 = "7b2a4d1d264e105eae49a27e2e78065b23e2e45724df2251eacdd317e95bfdfd",
strip_prefix = "rules_js-1.31.0",
url = "https://github.com/aspect-build/rules_js/releases/download/v1.31.0/rules_js-v1.31.0.tar.gz",
)
def js_rust_wasm_bindgen_register_toolchains(**kwargs):
_rust_wasm_bindgen_register_toolchains(**kwargs)

View File

View File

@ -0,0 +1,52 @@
"""Rust WASM-bindgen rules for interfacing with bazelbuild/rules_nodejs"""
load("@rules_nodejs//nodejs:providers.bzl", "DeclarationInfo", "JSModuleInfo")
load("//wasm_bindgen/private:wasm_bindgen.bzl", "WASM_BINDGEN_ATTR", "rust_wasm_bindgen_action")
def _nodejs_rust_wasm_bindgen_impl(ctx):
toolchain = ctx.toolchains[Label("//wasm_bindgen:toolchain_type")]
info = rust_wasm_bindgen_action(
ctx = ctx,
toolchain = toolchain,
wasm_file = ctx.attr.wasm_file,
target_output = ctx.attr.target,
bindgen_flags = ctx.attr.bindgen_flags,
)
# Return a structure that is compatible with the deps[] of a ts_library.
declarations = info.ts
es5_sources = info.js
return [
DefaultInfo(
files = depset([info.wasm], transitive = [info.js, info.ts]),
),
DeclarationInfo(
declarations = declarations,
transitive_declarations = declarations,
type_blocklisted_declarations = depset([]),
),
JSModuleInfo(
direct_sources = es5_sources,
sources = es5_sources,
),
info,
]
nodejs_rust_wasm_bindgen = rule(
doc = """\
Generates javascript and typescript bindings for a webassembly module using [wasm-bindgen][ws] that interface with [bazelbuild/rules_nodejs][bbnjs].
[ws]: https://rustwasm.github.io/docs/wasm-bindgen/
[bbnjs]: https://github.com/bazelbuild/rules_nodejs
An example of this rule in use can be seen at [@rules_rust//examples/wasm_bindgen/rules_js](../examples/wasm_bindgen/rules_js)
""",
implementation = _nodejs_rust_wasm_bindgen_impl,
attrs = WASM_BINDGEN_ATTR,
toolchains = [
str(Label("//wasm_bindgen:toolchain_type")),
],
incompatible_use_toolchain_transition = True,
)

View File

@ -0,0 +1,22 @@
"""TODO"""
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
load(
"//wasm_bindgen:repositories.bzl",
_rust_wasm_bindgen_dependencies = "rust_wasm_bindgen_dependencies",
_rust_wasm_bindgen_register_toolchains = "rust_wasm_bindgen_register_toolchains",
)
def nodejs_rust_wasm_bindgen_dependencies():
_rust_wasm_bindgen_dependencies()
maybe(
http_archive,
name = "rules_nodejs",
sha256 = "8fc8e300cb67b89ceebd5b8ba6896ff273c84f6099fc88d23f24e7102319d8fd",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/5.8.4/rules_nodejs-core-5.8.4.tar.gz"],
)
def nodejs_rust_wasm_bindgen_register_toolchains(**kwargs):
_rust_wasm_bindgen_register_toolchains(**kwargs)

View File

@ -1,190 +0,0 @@
# Copyright 2019 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Bazel rules for [wasm-bindgen](https://crates.io/crates/wasm-bindgen)"""
load("//rust:defs.bzl", "rust_common")
load(
"//wasm_bindgen:providers.bzl",
"DeclarationInfo",
"JSModuleInfo",
)
load("//wasm_bindgen/private:transitions.bzl", "wasm_bindgen_transition")
_WASM_BINDGEN_DOC = """\
Generates javascript and typescript bindings for a webassembly module using [wasm-bindgen][ws].
[ws]: https://rustwasm.github.io/docs/wasm-bindgen/
To use the Rust WebAssembly bindgen rules, add the following to your `WORKSPACE` file to add the
external repositories for the Rust bindgen toolchain (in addition to the Rust rules setup):
```python
load("@rules_rust//wasm_bindgen:repositories.bzl", "rust_wasm_bindgen_repositories")
rust_wasm_bindgen_repositories()
```
For more details on `rust_wasm_bindgen_repositories`, see [here](#rust_wasm_bindgen_repositories).
An example of this rule in use can be seen at [@rules_rust//examples/wasm](../examples/wasm)
"""
_WASM_BINDGEN_TOOLCHAIN_DOC = """\
The tools required for the `rust_wasm_bindgen` rule.
In cases where users want to control or change the version of `wasm-bindgen` used by [rust_wasm_bindgen](#rust_wasm_bindgen),
a unique toolchain can be created as in the example below:
```python
load("@rules_rust//bindgen:bindgen.bzl", "rust_bindgen_toolchain")
rust_bindgen_toolchain(
bindgen = "//3rdparty/crates:wasm_bindgen_cli__bin",
)
toolchain(
name = "wasm_bindgen_toolchain",
toolchain = "wasm_bindgen_toolchain_impl",
toolchain_type = "@rules_rust//wasm_bindgen:toolchain_type",
)
```
Now that you have your own toolchain, you need to register it by
inserting the following statement in your `WORKSPACE` file:
```python
register_toolchains("//my/toolchains:wasm_bindgen_toolchain")
```
For additional information, see the [Bazel toolchains documentation][toolchains].
[toolchains]: https://docs.bazel.build/versions/master/toolchains.html
"""
def _rust_wasm_bindgen_impl(ctx):
toolchain = ctx.toolchains[Label("//wasm_bindgen:wasm_bindgen_toolchain")]
bindgen_bin = toolchain.bindgen
# Since the `wasm_file` attribute is behind a transition, it will be converted
# to a list.
if len(ctx.attr.wasm_file) == 1 and rust_common.crate_info in ctx.attr.wasm_file[0]:
target = ctx.attr.wasm_file[0]
crate_info = target[rust_common.crate_info]
# Provide a helpful warning informing users how to use the rule
if rust_common.crate_info in target:
supported_types = ["cdylib", "bin"]
if crate_info.type not in supported_types:
fail("The target '{}' is not a supported type: {}".format(
ctx.attr.crate.label,
supported_types,
))
progress_message_label = target.label
input_file = crate_info.output
else:
progress_message_label = ctx.file.wasm_file.path
input_file = ctx.file.wasm_file
bindgen_wasm_module = ctx.actions.declare_file(ctx.attr.name + "_bg.wasm")
js_out = [ctx.actions.declare_file(ctx.attr.name + ".js")]
ts_out = [ctx.actions.declare_file(ctx.attr.name + ".d.ts")]
if ctx.attr.target == "bundler":
js_out.append(ctx.actions.declare_file(ctx.attr.name + "_bg.js"))
ts_out.append(ctx.actions.declare_file(ctx.attr.name + "_bg.wasm.d.ts"))
outputs = [bindgen_wasm_module] + js_out + ts_out
args = ctx.actions.args()
args.add("--target", ctx.attr.target)
args.add("--out-dir", bindgen_wasm_module.dirname)
args.add("--out-name", ctx.attr.name)
args.add_all(ctx.attr.bindgen_flags)
args.add(input_file)
ctx.actions.run(
executable = bindgen_bin,
inputs = [input_file],
outputs = outputs,
mnemonic = "RustWasmBindgen",
progress_message = "Generating WebAssembly bindings for {}...".format(progress_message_label),
arguments = [args],
)
# Return a structure that is compatible with the deps[] of a ts_library.
declarations = depset(ts_out)
es5_sources = depset(js_out)
return [
DefaultInfo(
files = depset(outputs),
),
DeclarationInfo(
declarations = declarations,
transitive_declarations = declarations,
type_blocklisted_declarations = depset([]),
),
JSModuleInfo(
direct_sources = es5_sources,
sources = es5_sources,
),
]
rust_wasm_bindgen = rule(
implementation = _rust_wasm_bindgen_impl,
doc = _WASM_BINDGEN_DOC,
attrs = {
"bindgen_flags": attr.string_list(
doc = "Flags to pass directly to the bindgen executable. See https://github.com/rustwasm/wasm-bindgen/ for details.",
),
"target": attr.string(
doc = "The type of output to generate. See https://rustwasm.github.io/wasm-bindgen/reference/deployment.html for details.",
default = "bundler",
values = ["web", "bundler", "nodejs", "no-modules", "deno"],
),
"wasm_file": attr.label(
doc = "The `.wasm` file or crate to generate bindings for.",
allow_single_file = True,
cfg = wasm_bindgen_transition,
mandatory = True,
),
"_allowlist_function_transition": attr.label(
default = Label("//tools/allowlists/function_transition_allowlist"),
),
},
toolchains = [
str(Label("//wasm_bindgen:wasm_bindgen_toolchain")),
],
incompatible_use_toolchain_transition = True,
)
def _rust_wasm_bindgen_toolchain_impl(ctx):
return platform_common.ToolchainInfo(
bindgen = ctx.executable.bindgen,
)
rust_wasm_bindgen_toolchain = rule(
implementation = _rust_wasm_bindgen_toolchain_impl,
doc = _WASM_BINDGEN_TOOLCHAIN_DOC,
attrs = {
"bindgen": attr.label(
doc = "The label of a `wasm-bindgen-cli` executable.",
executable = True,
cfg = "exec",
),
},
)