diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 94dcfe3fd..d466c0792 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -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/..." diff --git a/.github/workflows/formatting.yaml b/.github/workflows/formatting.yaml index afa94b6db..2b20b6563 100644 --- a/.github/workflows/formatting.yaml +++ b/.github/workflows/formatting.yaml @@ -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 diff --git a/.prettierrc.toml b/.prettierrc.toml new file mode 100644 index 000000000..c95475af6 --- /dev/null +++ b/.prettierrc.toml @@ -0,0 +1,3 @@ +# Prettier config file. For more opitons see https://prettier.io/docs/en/options +tabWidth = 4 +trailingComma = "all" diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index ad887672d..78251c3a8 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -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( diff --git a/docs/flatten.md b/docs/flatten.md index a2b8d0b52..e7e7cb467 100644 --- a/docs/flatten.md +++ b/docs/flatten.md @@ -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. | transitive_proc_macro_data | depset[File]: Data of all transitive proc-macro dependencies, and non-macro dependencies of those macros. | + + +## RustWasmBindgenInfo + +
+RustWasmBindgenInfo(js, ts, wasm)
+
+ +Info about wasm-bindgen outputs. + +**FIELDS** + + +| Name | Description | +| :------------- | :------------- | +| 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. | + + ## StdLibInfo diff --git a/docs/rust_wasm_bindgen.md b/docs/rust_wasm_bindgen.md index 9313d10fa..0f954a5f3 100644 --- a/docs/rust_wasm_bindgen.md +++ b/docs/rust_wasm_bindgen.md @@ -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 @@ -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] | bindgen | The label of a wasm-bindgen-cli executable. | Label | optional | None | + + +## RustWasmBindgenInfo + +
+RustWasmBindgenInfo(js, ts, wasm)
+
+ +Info about wasm-bindgen outputs. + +**FIELDS** + + +| Name | Description | +| :------------- | :------------- | +| 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. | + + ## rust_wasm_bindgen_dependencies diff --git a/docs/rust_wasm_bindgen.vm b/docs/rust_wasm_bindgen.vm index 13e78b166..bee382536 100644 --- a/docs/rust_wasm_bindgen.vm +++ b/docs/rust_wasm_bindgen.vm @@ -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 ]]# diff --git a/docs/symbols.bzl b/docs/symbols.bzl index a5f548776..8ea979abe 100644 --- a/docs/symbols.bzl +++ b/docs/symbols.bzl @@ -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 diff --git a/examples/WORKSPACE.bazel b/examples/WORKSPACE.bazel index 255b51d8f..253f255bb 100644 --- a/examples/WORKSPACE.bazel +++ b/examples/WORKSPACE.bazel @@ -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", diff --git a/examples/wasm/hello_world_wasm_test.js b/examples/wasm/hello_world_wasm_test.js deleted file mode 100644 index 87123353f..000000000 --- a/examples/wasm/hello_world_wasm_test.js +++ /dev/null @@ -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); - }); -}) diff --git a/examples/wasm/BUILD.bazel b/examples/wasm_bindgen/BUILD.bazel similarity index 76% rename from examples/wasm/BUILD.bazel rename to examples/wasm_bindgen/BUILD.bazel index 8fe065449..f8b7b0140 100644 --- a/examples/wasm/BUILD.bazel +++ b/examples/wasm_bindgen/BUILD.bazel @@ -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", -) diff --git a/examples/wasm_bindgen/hello_world_wasm_test.js b/examples/wasm_bindgen/hello_world_wasm_test.js new file mode 100644 index 000000000..f55b72ab1 --- /dev/null +++ b/examples/wasm_bindgen/hello_world_wasm_test.js @@ -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); + }); +}); diff --git a/examples/wasm/main.rs b/examples/wasm_bindgen/main.rs similarity index 100% rename from examples/wasm/main.rs rename to examples/wasm_bindgen/main.rs diff --git a/examples/wasm_bindgen/rules_js/BUILD.bazel b/examples/wasm_bindgen/rules_js/BUILD.bazel new file mode 100644 index 000000000..02988143b --- /dev/null +++ b/examples/wasm_bindgen/rules_js/BUILD.bazel @@ -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", +) diff --git a/examples/wasm_bindgen/rules_nodejs/BUILD.bazel b/examples/wasm_bindgen/rules_nodejs/BUILD.bazel new file mode 100644 index 000000000..200d506e5 --- /dev/null +++ b/examples/wasm_bindgen/rules_nodejs/BUILD.bazel @@ -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", +) diff --git a/wasm_bindgen/BUILD.bazel b/wasm_bindgen/BUILD.bazel index db37710b9..a5e7560c9 100644 --- a/wasm_bindgen/BUILD.bazel +++ b/wasm_bindgen/BUILD.bazel @@ -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"]), diff --git a/wasm_bindgen/defs.bzl b/wasm_bindgen/defs.bzl new file mode 100644 index 000000000..280c664e6 --- /dev/null +++ b/wasm_bindgen/defs.bzl @@ -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 diff --git a/wasm_bindgen/private/BUILD.bazel b/wasm_bindgen/private/BUILD.bazel index f719ebccc..9f217f8f9 100644 --- a/wasm_bindgen/private/BUILD.bazel +++ b/wasm_bindgen/private/BUILD.bazel @@ -4,6 +4,7 @@ bzl_library( name = "bzl_lib", srcs = [ "transitions.bzl", + "wasm_bindgen.bzl", ], visibility = ["//wasm_bindgen:__pkg__"], ) diff --git a/wasm_bindgen/private/wasm_bindgen.bzl b/wasm_bindgen/private/wasm_bindgen.bzl new file mode 100644 index 000000000..8607912b0 --- /dev/null +++ b/wasm_bindgen/private/wasm_bindgen.bzl @@ -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", + ), + }, +) diff --git a/wasm_bindgen/providers.bzl b/wasm_bindgen/providers.bzl index 74fc33300..06e434e89 100644 --- a/wasm_bindgen/providers.bzl +++ b/wasm_bindgen/providers.bzl @@ -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 diff --git a/wasm_bindgen/repositories.bzl b/wasm_bindgen/repositories.bzl index 113857969..4b62b3b17 100644 --- a/wasm_bindgen/repositories.bzl +++ b/wasm_bindgen/repositories.bzl @@ -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 diff --git a/wasm_bindgen/rules_js/BUILD.bazel b/wasm_bindgen/rules_js/BUILD.bazel new file mode 100644 index 000000000..a1ca18537 --- /dev/null +++ b/wasm_bindgen/rules_js/BUILD.bazel @@ -0,0 +1 @@ +"""Rust WASM-bindgen rules for interfacing with aspects/rules_js""" diff --git a/wasm_bindgen/rules_js/defs.bzl b/wasm_bindgen/rules_js/defs.bzl new file mode 100644 index 000000000..24a9ed1dc --- /dev/null +++ b/wasm_bindgen/rules_js/defs.bzl @@ -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, +) diff --git a/wasm_bindgen/rules_js/repositories.bzl b/wasm_bindgen/rules_js/repositories.bzl new file mode 100644 index 000000000..5372b5bbc --- /dev/null +++ b/wasm_bindgen/rules_js/repositories.bzl @@ -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) diff --git a/wasm_bindgen/rules_nodejs/BUILD.bazel b/wasm_bindgen/rules_nodejs/BUILD.bazel new file mode 100644 index 000000000..e69de29bb diff --git a/wasm_bindgen/rules_nodejs/defs.bzl b/wasm_bindgen/rules_nodejs/defs.bzl new file mode 100644 index 000000000..6ac417fb0 --- /dev/null +++ b/wasm_bindgen/rules_nodejs/defs.bzl @@ -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, +) diff --git a/wasm_bindgen/rules_nodejs/repositories.bzl b/wasm_bindgen/rules_nodejs/repositories.bzl new file mode 100644 index 000000000..e51eac349 --- /dev/null +++ b/wasm_bindgen/rules_nodejs/repositories.bzl @@ -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) diff --git a/wasm_bindgen/wasm_bindgen.bzl b/wasm_bindgen/wasm_bindgen.bzl deleted file mode 100644 index 219065d81..000000000 --- a/wasm_bindgen/wasm_bindgen.bzl +++ /dev/null @@ -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", - ), - }, -)