From fd48df3beaf7695bd01fb4de12e32c4b1b90bb28 Mon Sep 17 00:00:00 2001 From: Matt Stark Date: Mon, 19 Jun 2023 12:35:53 +1000 Subject: [PATCH 1/3] Bugfix: Use repo_name for apple_support. It's referred to in the code as build_bazel_apple_support. --- MODULE.bazel | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index ad73e240c2..712e99157c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -8,7 +8,11 @@ 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.1") 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( From d43a138d969ab8e58194b6892bf3def33c9f248a Mon Sep 17 00:00:00 2001 From: Matt Stark Date: Mon, 19 Jun 2023 13:14:52 +1000 Subject: [PATCH 2/3] Add a host tools repo. This is the same as the @toolchain__ repository. However, we need to define it seperately because otherwise we'd need to use_extension on every single toolchain. --- MODULE.bazel | 6 +++++ rust/extensions.bzl | 65 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 712e99157c..94b40d1c24 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -19,3 +19,9 @@ use_repo( internal_deps, "rules_rust_tinyjson", ) + +# This is the default host tools configuration, but if a user defines it in +# their repo, it's overridden. +rust = use_extension("//rust:extensions.bzl", "rust") +rust.host_tools(edition = "2021") +use_repo(rust, "rust_host_tools") diff --git a/rust/extensions.bzl b/rust/extensions.bzl index 883946c9ea..a6f873b410 100644 --- a/rust/extensions.bzl +++ b/rust/extensions.bzl @@ -1,15 +1,38 @@ "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] +def _rust_impl(module_ctx): + # Allow the root module to define host tools. Otherwise, we'll fall back to + # the one defined in rules_rust. + for mod in module_ctx.modules: + if mod.tags.host_tools: + host_tools = mod.tags.host_tools[0] + 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, + ) + break + + mod = module_ctx.modules[0] for toolchain in mod.tags.toolchain: rust_register_toolchains( dev_components = toolchain.dev_components, @@ -24,19 +47,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(default = rust_common.default_version), + **_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, + }, ) From 4528f3f1fb57c51d80576b9a7688fc5fb51ed298 Mon Sep 17 00:00:00 2001 From: Matt Stark Date: Mon, 19 Jun 2023 13:50:57 +1000 Subject: [PATCH 3/3] Support cargo_bazel_bootstrap for bzlmod --- MODULE.bazel | 18 ++- crate_universe/deps_bootstrap.bzl | 4 +- .../private/module_extensions/BUILD.bazel | 0 .../cargo_bazel_bootstrap.bzl | 14 +++ rust/extensions.bzl | 106 ++++++++++++++---- 5 files changed, 115 insertions(+), 27 deletions(-) create mode 100644 crate_universe/private/module_extensions/BUILD.bazel create mode 100644 crate_universe/private/module_extensions/cargo_bazel_bootstrap.bzl diff --git a/MODULE.bazel b/MODULE.bazel index 94b40d1c24..ce8366a337 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -20,8 +20,20 @@ use_repo( "rules_rust_tinyjson", ) -# This is the default host tools configuration, but if a user defines it in -# their repo, it's overridden. rust = use_extension("//rust:extensions.bzl", "rust") -rust.host_tools(edition = "2021") + +# 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") diff --git a/crate_universe/deps_bootstrap.bzl b/crate_universe/deps_bootstrap.bzl index 28f6d14b0d..e4fda6de97 100644 --- a/crate_universe/deps_bootstrap.bzl +++ b/crate_universe/deps_bootstrap.bzl @@ -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, @@ -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 ) diff --git a/crate_universe/private/module_extensions/BUILD.bazel b/crate_universe/private/module_extensions/BUILD.bazel new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crate_universe/private/module_extensions/cargo_bazel_bootstrap.bzl b/crate_universe/private/module_extensions/cargo_bazel_bootstrap.bzl new file mode 100644 index 0000000000..18a46eff25 --- /dev/null +++ b/crate_universe/private/module_extensions/cargo_bazel_bootstrap.bzl @@ -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.""", +) diff --git a/rust/extensions.bzl b/rust/extensions.bzl index a6f873b410..f45a557162 100644 --- a/rust/extensions.bzl +++ b/rust/extensions.bzl @@ -10,30 +10,90 @@ load( "DEFAULT_STATIC_RUST_URL_TEMPLATES", ) +_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 = "") +""" + _EXAMPLE_TOOLCHAIN + +_TOOLCHAIN_ERR = """ +Please add at least one toolchain to your root MODULE.bazel. For example: +""" + _EXAMPLE_TOOLCHAIN + def _rust_impl(module_ctx): - # Allow the root module to define host tools. Otherwise, we'll fall back to - # the one defined in rules_rust. + # 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.tags.host_tools: - host_tools = mod.tags.host_tools[0] - 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, - ) - break - - mod = module_ctx.modules[0] - for toolchain in mod.tags.toolchain: + 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, @@ -64,7 +124,7 @@ _RUST_TOOLCHAIN_TAG = tag_class(attrs = dict( )) _RUST_HOST_TOOLS_TAG = tag_class(attrs = dict( - version = attr.string(default = rust_common.default_version), + version = attr.string(), **_COMMON_TAG_KWARGS ))