Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support cargo_bazel_bootstrap for bzlmod #2021

Merged
merged 4 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
},
)
Loading