Skip to content

Commit

Permalink
Support bzlmod
Browse files Browse the repository at this point in the history
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
bazel run //:hello_world
```

A "hub" repository for toolchains is defined, and can be registered using:

```
register_toolchains("@rust_toolchains//:all")
```
  • Loading branch information
cameron-martin committed Feb 18, 2023
1 parent 20ce44e commit a3d7796
Show file tree
Hide file tree
Showing 10 changed files with 280 additions and 59 deletions.
23 changes: 23 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
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",
sha256 = "1a8304da9f9370f6a6f9020b7903b044aa9ce3470f300a1fba5bc77c78145a16",
version = "2.3.0",
)

use_repo(
raw_cargo,
rules_rust_tinyjson = "raw_cargo_tinyjson_2_3_0",
)
1 change: 1 addition & 0 deletions examples/bzlmod/hello_world/.bazelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build --experimental_enable_bzlmod
1 change: 1 addition & 0 deletions examples/bzlmod/hello_world/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/bazel-*
13 changes: 13 additions & 0 deletions examples/bzlmod/hello_world/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -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",
)
22 changes: 22 additions & 0 deletions examples/bzlmod/hello_world/MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module(
name = "hello_world",
version = "1.0",
)

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_toolchains",
)

register_toolchains("@rust_toolchains//:all")
Empty file.
17 changes: 17 additions & 0 deletions examples/bzlmod/hello_world/src/main.rs
Original file line number Diff line number Diff line change
@@ -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!");
}
45 changes: 45 additions & 0 deletions extensions.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"Module extensions for using rules_rust with bzlmod"

load("//rust:repositories.bzl", "rust_register_toolchains")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

def _toolchains_impl(ctx):
mod = ctx.modules[0]
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},
)
87 changes: 75 additions & 12 deletions rust/private/repository_utils.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -220,15 +220,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",
allocator_library = {allocator_library},
binary_ext = "{binary_ext}",
staticlib_ext = "{staticlib_ext}",
Expand All @@ -243,7 +243,6 @@ rust_toolchain(
"""

def BUILD_for_rust_toolchain(
workspace_name,
name,
exec_triple,
target_triple,
Expand All @@ -255,7 +254,6 @@ def BUILD_for_rust_toolchain(
"""Emits a toolchain declaration to match an existing compiler and stdlib.
Args:
workspace_name (str): The name of the workspace that this toolchain resides in
name (str): The name of the toolchain declaration
exec_triple (triple): The rust-style target that this compiler runs on
target_triple (triple): The rust-style target triple of the tool
Expand All @@ -276,19 +274,18 @@ def BUILD_for_rust_toolchain(

rustfmt_label = "None"
if include_rustfmt:
rustfmt_label = "\"@{workspace_name}//:rustfmt_bin\"".format(workspace_name = workspace_name)
rustfmt_label = "\"//:rustfmt_bin\""
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\""
llvm_profdata_label = "\"//:llvm_profdata_bin\""
allocator_library_label = "None"
if allocator_library:
allocator_library_label = "\"{allocator_library}\"".format(allocator_library = allocator_library)

return _build_file_for_rust_toolchain_template.format(
toolchain_name = name,
workspace_name = workspace_name,
binary_ext = system_to_binary_ext(target_triple.system),
staticlib_ext = system_to_staticlib_ext(target_triple.system),
dylib_ext = system_to_dylib_ext(target_triple.system),
Expand All @@ -310,6 +307,7 @@ toolchain(
target_compatible_with = {target_constraint_sets_serialized},
toolchain = "{toolchain}",
toolchain_type = "{toolchain_type}",
visibility = ["//visibility:public"],
{target_settings}
)
"""
Expand Down Expand Up @@ -774,3 +772,68 @@ def select_rust_version(versions):
current = ver

return current

_build_file_for_toolchain_hub_template = """
toolchain(
name = "{name}",
exec_compatible_with = {exec_constraint_sets_serialized},
target_compatible_with = {target_constraint_sets_serialized},
toolchain = "{toolchain}",
toolchain_type = "{toolchain_type}",
visibility = ["//visibility:public"],
)
"""

def BUILD_for_toolchain_hub(
toolchain_names,
toolchain_labels,
toolchain_types,
target_compatible_with,
exec_compatible_with):
return "\n".join([_build_file_for_toolchain_hub_template.format(
name = toolchain_name,
exec_constraint_sets_serialized = json.encode(exec_compatible_with[toolchain_name]),
target_constraint_sets_serialized = json.encode(target_compatible_with[toolchain_name]),
toolchain = toolchain_labels[toolchain_name],
toolchain_type = toolchain_types[toolchain_name],
) for toolchain_name in toolchain_names])

def _toolchain_repository_hub_impl(repository_ctx):
repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
repository_ctx.name,
))

repository_ctx.file("BUILD.bazel", BUILD_for_toolchain_hub(
toolchain_names = repository_ctx.attr.toolchain_names,
toolchain_labels = repository_ctx.attr.toolchain_labels,
toolchain_types = repository_ctx.attr.toolchain_types,
target_compatible_with = repository_ctx.attr.target_compatible_with,
exec_compatible_with = repository_ctx.attr.exec_compatible_with,
))

toolchain_repository_hub = repository_rule(
doc = (
"Generates a toolchain-bearing repository that declares a set of other toolchains from other " +
"repositories. This exists to allow registering a set of toolchains in one go with the `:all` target."
),
attrs = {
"toolchain_names": attr.string_list(mandatory = True),
"exec_compatible_with": attr.string_list_dict(
doc = "A list of constraints for the execution platform for this toolchain, keyed by toolchain name.",
mandatory = True,
),
"target_compatible_with": attr.string_list_dict(
doc = "A list of constraints for the target platform for this toolchain, keyed by toolchain name.",
mandatory = True,
),
"toolchain_labels": attr.string_dict(
doc = "The name of the toolchain implementation target, keyed by toolchain name.",
mandatory = True,
),
"toolchain_types": attr.string_dict(
doc = "The toolchain type of the toolchain to declare, keyed by toolchain name.",
mandatory = True,
),
},
implementation = _toolchain_repository_hub_impl,
)
Loading

0 comments on commit a3d7796

Please sign in to comment.