Skip to content

Commit

Permalink
Support cargo_bazel_bootstrap for bzlmod (#2021)
Browse files Browse the repository at this point in the history
I've pulled out some of the code from
#1910 into a seperate PR,
to simplify the review process.

---------

Co-authored-by: scentini <[email protected]>
  • Loading branch information
matts1 and scentini authored Oct 25, 2023
1 parent cd3e53e commit 535af8b
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 18 deletions.
24 changes: 23 additions & 1 deletion MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,32 @@ print("WARNING: The rules_rust Bazel module is still highly experimental and sub
bazel_dep(name = "platforms", version = "0.0.7")
bazel_dep(name = "rules_cc", version = "0.0.9")
bazel_dep(name = "bazel_skylib", version = "1.2.0")
bazel_dep(name = "apple_support", version = "1.3.1")
bazel_dep(
name = "apple_support",
version = "1.3.1",
repo_name = "build_bazel_apple_support",
)

internal_deps = use_extension("//rust/private:extensions.bzl", "internal_deps")
use_repo(
internal_deps,
"rules_rust_tinyjson",
)

rust = use_extension("//rust:extensions.bzl", "rust")

# Allow us to run, for example, "bazel build //tools/runfiles" with bzlmod.
# Register it as a dev dependency so that we don't force this toolchain on
# downstream users.
rust.toolchain(edition = "2021")
use_repo(rust, "rust_toolchains")

register_toolchains(
"@rust_toolchains//:all",
dev_dependency = True,
)

use_repo(rust, "rust_host_tools")

cargo_bazel_bootstrap = use_extension("//crate_universe/private/module_extensions:cargo_bazel_bootstrap.bzl", "cargo_bazel_bootstrap")
use_repo(cargo_bazel_bootstrap, "cargo_bazel_bootstrap")
4 changes: 3 additions & 1 deletion crate_universe/deps_bootstrap.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ load("//crate_universe/private:srcs.bzl", "CARGO_BAZEL_SRCS")
# buildifier: disable=bzl-visibility
load("//rust/private:common.bzl", "rust_common")

def cargo_bazel_bootstrap(name = "cargo_bazel_bootstrap", rust_version = rust_common.default_version):
def cargo_bazel_bootstrap(name = "cargo_bazel_bootstrap", rust_version = rust_common.default_version, **kwargs):
"""An optional repository which bootstraps `cargo-bazel` for use with `crates_repository`
Args:
name (str, optional): The name of the `cargo_bootstrap_repository`.
rust_version (str, optional): The rust version to use. Defaults to the default of `cargo_bootstrap_repository`.
**kwargs: kwargs to pass through to cargo_bootstrap_repository.
"""
cargo_bootstrap_repository(
name = name,
Expand All @@ -22,4 +23,5 @@ def cargo_bazel_bootstrap(name = "cargo_bazel_bootstrap", rust_version = rust_co
version = rust_version,
# The increased timeout helps avoid flakes in CI
timeout = 900,
**kwargs
)
Empty file.
14 changes: 14 additions & 0 deletions crate_universe/private/module_extensions/cargo_bazel_bootstrap.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Module extension for bootstrapping cargo-bazel."""

load("//crate_universe:deps_bootstrap.bzl", _cargo_bazel_bootstrap_repo_rule = "cargo_bazel_bootstrap")

def _cargo_bazel_bootstrap_impl(_):
_cargo_bazel_bootstrap_repo_rule(
rust_toolchain_cargo_template = "@rust_host_tools//:bin/{tool}",
rust_toolchain_rustc_template = "@rust_host_tools//:bin/{tool}",
)

cargo_bazel_bootstrap = module_extension(
implementation = _cargo_bazel_bootstrap_impl,
doc = """Module extension to generate the cargo_bazel binary.""",
)
127 changes: 111 additions & 16 deletions rust/extensions.bzl
Original file line number Diff line number Diff line change
@@ -1,16 +1,99 @@
"Module extensions for using rules_rust with bzlmod"

load("//rust:defs.bzl", "rust_common")
load("//rust:repositories.bzl", "rust_register_toolchains", "rust_toolchain_tools_repository")
load("//rust/platform:triple.bzl", "get_host_triple")
load(
"//rust/private:repository_utils.bzl",
"DEFAULT_EXTRA_TARGET_TRIPLES",
"DEFAULT_NIGHTLY_VERSION",
"DEFAULT_STATIC_RUST_URL_TEMPLATES",
)
load(":repositories.bzl", "rust_register_toolchains")

def _rust_impl(ctx):
mod = ctx.modules[0]
for toolchain in mod.tags.toolchain:
_HOST_TOOL_ERR = """When %s, host tools must be explicitly defined. For example:
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.host_tools(
edition = "2021",
version = "1.70.2",
)
"""

_EXAMPLE_TOOLCHAIN = """
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(
edition = "2021",
versions = ["1.70.2"],
)
use_repo(rust, "rust_toolchains")
register_toolchains("@rust_toolchains//:all")"""

_TRANSITIVE_DEP_ERR = """
Your transitive dependency %s is using rules_rust, so you need to define a rust toolchain.
To do so, you will need to add the following to your root MODULE.bazel. For example:
bazel_dep(name = "rules_rust", version = "<rules_rust version>")
""" + _EXAMPLE_TOOLCHAIN

_TOOLCHAIN_ERR = """
Please add at least one toolchain to your root MODULE.bazel. For example:
""" + _EXAMPLE_TOOLCHAIN

def _rust_impl(module_ctx):
# Toolchain configuration is only allowed in the root module.
# It would be very confusing (and a security concern) if I was using the
# default rust toolchains, then when I added a module built on rust, I was
# suddenly using a custom rustc.
root = None
for mod in module_ctx.modules:
if mod.is_root:
root = mod
if not root:
fail(_TRANSITIVE_DEP_ERR % module_ctx.modules[0].name)

toolchains = root.tags.toolchain
if not toolchains:
fail(_TOOLCHAIN_ERR)

if len(root.tags.host_tools) == 1:
host_tools = root.tags.host_tools[0]
elif not root.tags.host_tools:
if len(toolchains) != 1:
fail(_HOST_TOOL_ERR % "multiple toolchains are provided")
toolchain = toolchains[0]
if len(toolchain.versions) == 1:
version = toolchain.versions[0]
elif not toolchain.versions:
version = None
else:
fail(_HOST_TOOL_ERR % "multiple toolchain versions are provided")
host_tools = struct(
allocator_library = toolchain.allocator_library,
dev_components = toolchain.dev_components,
edition = toolchain.edition,
rustfmt_version = toolchain.rustfmt_version,
sha256s = toolchain.sha256s,
urls = toolchain.urls,
version = version,
)
else:
fail("Multiple host_tools were defined in your root MODULE.bazel")

host_triple = get_host_triple(module_ctx)
rust_toolchain_tools_repository(
name = "rust_host_tools",
exec_triple = host_triple.str,
target_triple = host_triple.str,
allocator_library = host_tools.allocator_library,
dev_components = host_tools.dev_components,
edition = host_tools.edition,
rustfmt_version = host_tools.rustfmt_version,
sha256s = host_tools.sha256s,
urls = host_tools.urls,
version = host_tools.version or rust_common.default_version,
)

for toolchain in toolchains:
rust_register_toolchains(
dev_components = toolchain.dev_components,
edition = toolchain.edition,
Expand All @@ -24,19 +107,31 @@ def _rust_impl(ctx):
register_toolchains = False,
)

rust_toolchain = tag_class(attrs = {
"allocator_library": attr.string(default = "@rules_rust//ffi/cc/allocator_library"),
"dev_components": attr.bool(default = False),
"edition": attr.string(),
"extra_target_triples": attr.string_list(default = DEFAULT_EXTRA_TARGET_TRIPLES),
"rust_analyzer_version": attr.string(),
"rustfmt_version": attr.string(default = DEFAULT_NIGHTLY_VERSION),
"sha256s": attr.string_dict(),
"urls": attr.string_list(default = DEFAULT_STATIC_RUST_URL_TEMPLATES),
"versions": attr.string_list(default = []),
})
_COMMON_TAG_KWARGS = dict(
allocator_library = attr.string(default = "@rules_rust//ffi/cc/allocator_library"),
dev_components = attr.bool(default = False),
edition = attr.string(),
rustfmt_version = attr.string(default = DEFAULT_NIGHTLY_VERSION),
sha256s = attr.string_dict(),
urls = attr.string_list(default = DEFAULT_STATIC_RUST_URL_TEMPLATES),
)

_RUST_TOOLCHAIN_TAG = tag_class(attrs = dict(
extra_target_triples = attr.string_list(default = DEFAULT_EXTRA_TARGET_TRIPLES),
rust_analyzer_version = attr.string(),
versions = attr.string_list(default = []),
**_COMMON_TAG_KWARGS
))

_RUST_HOST_TOOLS_TAG = tag_class(attrs = dict(
version = attr.string(),
**_COMMON_TAG_KWARGS
))

rust = module_extension(
implementation = _rust_impl,
tag_classes = {"toolchain": rust_toolchain},
tag_classes = {
"host_tools": _RUST_HOST_TOOLS_TAG,
"toolchain": _RUST_TOOLCHAIN_TAG,
},
)

0 comments on commit 535af8b

Please sign in to comment.