blob: 43aa25eb3a63bda2d785c8f64a542e783c48f9dd [file] [edit]
# Part of the Crubit project, under the Apache License v2.0 with LLVM
# Exceptions. See /LICENSE for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
"""Module extension for configuring Crubit toolchains."""
load("@toolchains_llvm//toolchain:rules.bzl", "llvm_toolchain")
load("//bazel:llvm_version_check.bzl", "llvm_version_check")
# buildifier: disable=bzl-visibility
load("@rules_rust//rust/private:repositories.bzl", "DEFAULT_TOOLCHAIN_TRIPLES", "rust_register_toolchains")
# buildifier: disable=bzl-visibility
load(
"@rules_rust//rust/private:repository_utils.bzl",
"DEFAULT_EXTRA_TARGET_TRIPLES",
"DEFAULT_STATIC_RUST_URL_TEMPLATES",
)
# These attributes are mirrored from rules_rust's toolchain tag to allow
# configuration without duplicating the implementation logic.
_RUST_TAG_ATTRS = {
"rust_version": attr.string(doc = "The version of Rust to install."),
"edition": attr.string(doc = "The rust edition to be used by default.", default = "2024"),
"dev_components": attr.bool(doc = "Whether to download the rustc-dev components.", default = True),
"extra_rustc_flags": attr.string_list(doc = "Extra flags to pass to rustc in non-exec configuration."),
"extra_exec_rustc_flags": attr.string_list(doc = "Extra flags to pass to rustc in exec configuration."),
"rustfmt_version": attr.string(doc = "The version of rustfmt."),
"rust_analyzer_version": attr.string(doc = "The version of rust-analyzer."),
"sha256s": attr.string_dict(doc = "A dict associating tool subdirectories to sha256 hashes."),
"extra_target_triples": attr.string_list(doc = "Additional rust-style targets.", default = DEFAULT_EXTRA_TARGET_TRIPLES),
"opt_level": attr.string_dict(doc = "Rustc optimization levels."),
"strip_level": attr.string_dict(doc = "Rustc strip levels."),
"urls": attr.string_list(doc = "A list of mirror urls.", default = DEFAULT_STATIC_RUST_URL_TEMPLATES),
"allocator_library": attr.label(doc = "Target that provides allocator functions."),
"global_allocator_library": attr.label(doc = "Target that provides allocator functions when global allocator is used."),
"target_settings": attr.label_list(doc = "Config settings for toolchain selection."),
"aliases": attr.string_dict(doc = "Toolchain repository aliases."),
}
_LLVM_TAG_ATTRS = {
"llvm_version": attr.string(doc = "The version of LLVM to install."),
"llvm_urls": attr.string_list(doc = "Custom URLs for LLVM distribution."),
"llvm_sha256": attr.string(doc = "SHA256 for LLVM distribution."),
"llvm_strip_prefix": attr.string(doc = "Strip prefix for LLVM distribution."),
}
def _crubit_toolchains_impl(ctx):
# Prefer configuration from the root module.
config = None
for mod in ctx.modules:
if mod.is_root and mod.tags.configure:
config = mod.tags.configure[0]
break
if not config:
for mod in ctx.modules:
if mod.tags.configure:
config = mod.tags.configure[0]
break
# 1. Coordinate versions
rust_version = getattr(config, "rust_version", None)
if not rust_version:
fail("Please specify a Rust version with the `rust_version` attribute.")
# 2. Define LLVM repository
final_llvm_version = getattr(config, "llvm_version", None)
final_urls = getattr(config, "llvm_urls", None)
final_sha256 = getattr(config, "llvm_sha256", None)
final_strip_prefix = getattr(config, "llvm_strip_prefix", None)
# Perform LLVM version check against system rustc
llvm_version_check(
name = "llvm_version_check",
llvm_version = final_llvm_version,
)
if not final_urls and not final_llvm_version:
fail("Please specify an LLVM version or a custom LLVM via llvm_urls, llvm_sha256, and llvm_strip_prefix.")
elif final_urls:
llvm_toolchain(
name = "llvm_toolchain",
llvm_version = final_llvm_version,
urls = {"": final_urls},
sha256 = {"": final_sha256},
strip_prefix = {"": final_strip_prefix},
)
else:
llvm_toolchain(
name = "llvm_toolchain",
llvm_version = final_llvm_version,
)
# 3. Define Rust repository (delegated to rules_rust)
rust_kwargs = {}
if config:
rust_kwargs = {k: getattr(config, k) for k in _RUST_TAG_ATTRS.keys() if k != "rust_version"}
else:
# Defaults if no configure tag is present
rust_kwargs = {
"edition": "2024",
"extra_target_triples": DEFAULT_EXTRA_TARGET_TRIPLES,
"urls": DEFAULT_STATIC_RUST_URL_TEMPLATES,
}
# We need to always include dev components because Crubit needs them internally.
rust_kwargs["dev_components"] = True
# Stringify labels as required by the underlying repository rules
if rust_kwargs.get("allocator_library"):
rust_kwargs["allocator_library"] = str(rust_kwargs["allocator_library"])
if rust_kwargs.get("global_allocator_library"):
rust_kwargs["global_allocator_library"] = str(rust_kwargs["global_allocator_library"])
if rust_kwargs.get("target_settings"):
rust_kwargs["target_settings"] = [str(s) for s in rust_kwargs["target_settings"]]
rust_register_toolchains(
hub_name = "rust_toolchains",
versions = [rust_version],
toolchain_triples = dict(DEFAULT_TOOLCHAIN_TRIPLES),
rustfmt_toolchain_triples = DEFAULT_TOOLCHAIN_TRIPLES,
compact_windows_names = True,
**rust_kwargs
)
crubit_toolchains = module_extension(
implementation = _crubit_toolchains_impl,
tag_classes = {
"configure": tag_class(
attrs = _RUST_TAG_ATTRS | _LLVM_TAG_ATTRS,
),
},
)