From c0fad5efbaaac27a3c27e1437f55970cea0d947d Mon Sep 17 00:00:00 2001 From: Cameron Martin Date: Thu, 25 Aug 2022 18:54:51 +0100 Subject: [PATCH] Support bzlmod This is a rough proof of concept of making rules_rust load dependencies via bzlmod. Currently it can only compile and run rust crates, and cannot load crates from Cargo.toml. There is one new module, `examples/bzlmod/hello_world`, that depends on the root `rules_rust` module. This example can be built and run using: ``` cd examples/bzlmod/hello_world USE_BAZEL_VERSION=last_green bazel run //:hello_world ``` Currently toolchain registration has quite bad user experience, because all the toolchains to register have to be listed by the user in the MODULE.bazel file. This is because module extensions cannot directly register toolchains and instead must only expose repositories with toolchains, that are then registered using `toolchains_to_register`. It would be nice if all the toolchains could be aliased to one label and them all registered together. However, I can't see how this would be possible. --- MODULE.bazel | 14 ++++++++ examples/bzlmod/hello_world/.bazelrc | 1 + examples/bzlmod/hello_world/.gitignore | 1 + examples/bzlmod/hello_world/BUILD.bazel | 13 +++++++ examples/bzlmod/hello_world/MODULE.bazel | 13 +++++++ examples/bzlmod/hello_world/WORKSPACE | 0 examples/bzlmod/hello_world/src/main.rs | 17 +++++++++ extensions.bzl | 45 ++++++++++++++++++++++++ rust/private/repository_utils.bzl | 20 +++++------ rust/repositories.bzl | 34 +++++++++--------- 10 files changed, 131 insertions(+), 27 deletions(-) create mode 100644 MODULE.bazel create mode 100644 examples/bzlmod/hello_world/.bazelrc create mode 100644 examples/bzlmod/hello_world/.gitignore create mode 100644 examples/bzlmod/hello_world/BUILD.bazel create mode 100644 examples/bzlmod/hello_world/MODULE.bazel create mode 100644 examples/bzlmod/hello_world/WORKSPACE create mode 100644 examples/bzlmod/hello_world/src/main.rs create mode 100644 extensions.bzl diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000000..a125239793 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,14 @@ +module( + name = "rules_rust", + version = "0.9.0", +) + +bazel_dep(name = "platforms", version = "0.0.5") +bazel_dep(name = "rules_cc", version = "0.0.1") +bazel_dep(name = "bazel_skylib", version = "1.2.0") +bazel_dep(name = "apple_support", version = "0.13.0") + +# Load tinyjson without using the process wrapper +raw_cargo = use_extension("//:extensions.bzl", "raw_cargo") +raw_cargo.crate(name = "tinyjson", version = "2.3.0", sha256 = "1a8304da9f9370f6a6f9020b7903b044aa9ce3470f300a1fba5bc77c78145a16") +use_repo(raw_cargo, rules_rust_tinyjson = "raw_cargo_tinyjson_2_3_0") diff --git a/examples/bzlmod/hello_world/.bazelrc b/examples/bzlmod/hello_world/.bazelrc new file mode 100644 index 0000000000..c8428d9570 --- /dev/null +++ b/examples/bzlmod/hello_world/.bazelrc @@ -0,0 +1 @@ +build --experimental_enable_bzlmod \ No newline at end of file diff --git a/examples/bzlmod/hello_world/.gitignore b/examples/bzlmod/hello_world/.gitignore new file mode 100644 index 0000000000..65e8edca79 --- /dev/null +++ b/examples/bzlmod/hello_world/.gitignore @@ -0,0 +1 @@ +/bazel-* \ No newline at end of file diff --git a/examples/bzlmod/hello_world/BUILD.bazel b/examples/bzlmod/hello_world/BUILD.bazel new file mode 100644 index 0000000000..3e2ec1932e --- /dev/null +++ b/examples/bzlmod/hello_world/BUILD.bazel @@ -0,0 +1,13 @@ +load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_doc") + +package(default_visibility = ["//visibility:public"]) + +rust_binary( + name = "hello_world", + srcs = ["src/main.rs"], +) + +rust_doc( + name = "hello_world_doc", + crate = ":hello_world", +) diff --git a/examples/bzlmod/hello_world/MODULE.bazel b/examples/bzlmod/hello_world/MODULE.bazel new file mode 100644 index 0000000000..56b34a5f11 --- /dev/null +++ b/examples/bzlmod/hello_world/MODULE.bazel @@ -0,0 +1,13 @@ +module( + name = "hello_world", + version = "1.0", + toolchains_to_register = ["@rust_linux_x86_64__x86_64-unknown-linux-gnu//:toolchain"], +) + +bazel_dep(name = "rules_rust", version = "0.9.0") + +local_path_override(module_name = "rules_rust", path = "../../..") + +rust_toolchains = use_extension("@rules_rust//:extensions.bzl", "toolchains") +rust_toolchains.toolchain(edition = "2021") +use_repo(rust_toolchains, "rust_linux_x86_64__x86_64-unknown-linux-gnu") \ No newline at end of file diff --git a/examples/bzlmod/hello_world/WORKSPACE b/examples/bzlmod/hello_world/WORKSPACE new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/bzlmod/hello_world/src/main.rs b/examples/bzlmod/hello_world/src/main.rs new file mode 100644 index 0000000000..317f564583 --- /dev/null +++ b/examples/bzlmod/hello_world/src/main.rs @@ -0,0 +1,17 @@ +// Copyright 2015 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. + +fn main() { + println!("Hello, world!"); +} diff --git a/extensions.bzl b/extensions.bzl new file mode 100644 index 0000000000..8a1839b744 --- /dev/null +++ b/extensions.bzl @@ -0,0 +1,45 @@ +load("//rust:repositories.bzl", "rust_register_toolchains") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +def _toolchains_impl(ctx): + for mod in ctx.modules: + for toolchain in mod.tags.toolchain: + rust_register_toolchains(edition = toolchain.edition, register_toolchains = False) + +toolchains_toolchain = tag_class(attrs = {"edition": attr.string()}) +toolchains = module_extension( + implementation=_toolchains_impl, + tag_classes={"toolchain": toolchains_toolchain}, +) + +def _create_build_file_content(name): + return """ +load("@rules_rust//rust/private:rust.bzl", "rust_library_without_process_wrapper") + +rust_library_without_process_wrapper( + name = "{}", + srcs = glob(["src/*.rs"]), + edition = "2018", + visibility = ["@rules_rust//util/process_wrapper:__pkg__"], +) +""".format(name) + +def _raw_cargo_impl(ctx): + for mod in ctx.modules: + for crate in mod.tags.crate: + http_archive( + name = "raw_cargo_{}_{}".format(crate.name, crate.version.replace(".", "_")), + sha256 = crate.sha256, + url = "https://crates.io/api/v1/crates/{}/{}/download".format(crate.name, crate.version), + strip_prefix = "{}-{}".format(crate.name, crate.version), + type = "tar.gz", + build_file_content = _create_build_file_content(crate.name), + ) + +raw_cargo_crate = tag_class(attrs = {"name": attr.string(), "version": attr.string(), "sha256": attr.string()}) +raw_cargo = module_extension( + implementation=_raw_cargo_impl, + tag_classes={"crate": raw_cargo_crate}, +) + + diff --git a/rust/private/repository_utils.bzl b/rust/private/repository_utils.bzl index 86d3f78ace..35e0f87e54 100644 --- a/rust/private/repository_utils.bzl +++ b/rust/private/repository_utils.bzl @@ -205,15 +205,15 @@ load("@rules_rust//rust:toolchain.bzl", "rust_toolchain") rust_toolchain( name = "{toolchain_name}", - rust_doc = "@{workspace_name}//:rustdoc", - rust_std = "@{workspace_name}//:rust_std-{target_triple}", - rustc = "@{workspace_name}//:rustc", + rust_doc = "//:rustdoc", + rust_std = "//:rust_std-{target_triple}", + rustc = "//:rustc", rustfmt = {rustfmt_label}, - cargo = "@{workspace_name}//:cargo", - clippy_driver = "@{workspace_name}//:clippy_driver_bin", + cargo = "//:cargo", + clippy_driver = "//:clippy_driver_bin", llvm_cov = {llvm_cov_label}, llvm_profdata = {llvm_profdata_label}, - rustc_lib = "@{workspace_name}//:rustc_lib", + rustc_lib = "//:rustc_lib", rustc_srcs = {rustc_srcs}, allocator_library = {allocator_library}, binary_ext = "{binary_ext}", @@ -265,15 +265,15 @@ def BUILD_for_rust_toolchain( rustc_srcs = "None" if include_rustc_srcs: - rustc_srcs = "\"@{workspace_name}//lib/rustlib/src:rustc_srcs\"".format(workspace_name = workspace_name) + rustc_srcs = "\"//lib/rustlib/src:rustc_srcs\"".format(workspace_name = workspace_name) rustfmt_label = "None" if include_rustfmt: - rustfmt_label = "\"@{workspace_name}//:rustfmt_bin\"".format(workspace_name = workspace_name) + rustfmt_label = "\"//:rustfmt_bin\"".format(workspace_name = workspace_name) llvm_cov_label = "None" llvm_profdata_label = "None" if include_llvm_tools: - llvm_cov_label = "\"@{workspace_name}//:llvm_cov_bin\"".format(workspace_name = workspace_name) - llvm_profdata_label = "\"@{workspace_name}//:llvm_profdata_bin\"".format(workspace_name = workspace_name) + llvm_cov_label = "\"//:llvm_cov_bin\"".format(workspace_name = workspace_name) + llvm_profdata_label = "\"//:llvm_profdata_bin\"".format(workspace_name = workspace_name) allocator_library_label = "None" if allocator_library: allocator_library_label = "\"{allocator_library}\"".format(allocator_library = allocator_library) diff --git a/rust/repositories.bzl b/rust/repositories.bzl index 77b4bac5bc..0dfd4fea45 100644 --- a/rust/repositories.bzl +++ b/rust/repositories.bzl @@ -610,20 +610,20 @@ def rust_repository_set( native.register_toolchains(*all_toolchain_names) native.register_toolchains(str(Label("//rust/private/dummy_cc_toolchain:dummy_cc_wasm32_toolchain"))) - # Inform users that they should be using the canonical name if it's not detected - if "rules_rust" not in native.existing_rules(): - message = "\n" + ("=" * 79) + "\n" - message += ( - "It appears that you are trying to import rules_rust without using its\n" + - "canonical name, \"@rules_rust\" Please change your WORKSPACE file to\n" + - "import this repo with `name = \"rules_rust\"` instead." - ) - - if "io_bazel_rules_rust" in native.existing_rules(): - message += "\n\n" + ( - "Note that the previous name of \"@io_bazel_rules_rust\" is deprecated.\n" + - "See https://github.com/bazelbuild/rules_rust/issues/499 for context." - ) - - message += "\n" + ("=" * 79) - fail(message) + # # Inform users that they should be using the canonical name if it's not detected + # if "rules_rust" not in native.existing_rules(): + # message = "\n" + ("=" * 79) + "\n" + # message += ( + # "It appears that you are trying to import rules_rust without using its\n" + + # "canonical name, \"@rules_rust\" Please change your WORKSPACE file to\n" + + # "import this repo with `name = \"rules_rust\"` instead." + # ) + + # if "io_bazel_rules_rust" in native.existing_rules(): + # message += "\n\n" + ( + # "Note that the previous name of \"@io_bazel_rules_rust\" is deprecated.\n" + + # "See https://github.com/bazelbuild/rules_rust/issues/499 for context." + # ) + + # message += "\n" + ("=" * 79) + # fail(message)