Skip to content
README.md 3.44 KiB
Newer Older
# `rules_toolchain`
Matthew Clarkson's avatar
Matthew Clarkson committed

> A Bazel ruleset to enable concise toolchain registration.
Matthew Clarkson's avatar
Matthew Clarkson committed

## Getting Started
Matthew Clarkson's avatar
Matthew Clarkson committed

Add the following to `MODULE.bazel`:
Matthew Clarkson's avatar
Matthew Clarkson committed

which = use_repo_rule("@rules_toolchain//toolchain:defs.bzl", "toolchain_local_which")
which("echo")
```

The `echo` tool will be found on the `PATH`.

A repository with the `@echo//:echo` target will be created.

### Downloaded Tool

Use `rules_download` to provide a hermetic, pre-built binary in `MODULE.bazel`

```py
archive = use_repo_rule("@rules_download//download:defs.bzl", "download_archive")
archive(
    name = "coreutils-arm64-linux-gnu",
    srcs = ["coreutils"],
    integrity = "sha256-mlmkbeabyu4+5+cFiUSL6Ki4KFNqWu48gTjFc3NS43g=",
    strip_prefix = "coreutils-0.0.21-aarch64-unknown-linux-gnu",
    urls = ["https://github.com/uutils/coreutils/releases/download/0.0.21/coreutils-0.0.21-aarch64-unknown-linux-gnu.tar.gz"],
)
Matthew Clarkson's avatar
Matthew Clarkson committed
```

A repository with the `@coreutils-arm64-linux-gnu//:coreutils` target will be created.

### Toolchains

Create a `toolchain/echo/BUILD.bazel` with the following:

```py
load("@rules_toolchain//toolchain:defs.bzl", "toolchain_symlink_target", "toolchain_test")

# Custom rule, described in the next section
load(":resolved.bzl", "resolved")

# The `toolchain/echo:type` for registration
toolchain_type(
    name = "type",
)

# Register the `local` binary as a toolchain
# No `exec_compatible_with` constraints are needed as a local binary is always compatible with the execution platform
toolchain(
    name = "local",
    toolchain = "@echo",
    toolchain_type = ":type",
)

# Create a toolchain binary from the downloaded `coreutils`
toolchain_symlink_target(
    name = "coreutils-arm64-linux-gnu",
    target = "@coreutils-arm64-linux-gnu//:coreutils",
)

# Create a symlink to the multi-call binary
toolchain_symlink_target(
    name = "echo-arm64-linux-gnu",
    basename = "echo",
    target = ":coreutils-arm64-linux-gnu",
)

# Register the hermetic toolchain
# Use constraints to signify what host machines the toolchain is compatible with
toolchain(
    name = "arm64-linux",
    toolchain = ":echo-arm64-linux-gnu",
    toolchain_type = ":type",
    exec_compatible_with = [
        "@rules_toolchain//toolchain/constraint/cpu:arm64",
        "@rules_toolchain//toolchain/constraint/os:linux",
        # Bazel _assumes_ `glibc` for Linux
        # "@rules_toolchain//toolchain/constraint/libc:gnu",
    ],
)

# Provide a resolved toolchain target
resolved(
    name = "resolved",
    toolchain_type = ":type",
)
```

#### Resolved

To work around a [quirk in Bazel][resolved], the resolution of the toolchain must be defined in a separate rule.

`@rules_toolchain` provides the necessary building blocks for this rule.

Create `toolchain/echo/resolved.bzl` to provide the `resolved` rule that is used above:

```py
load("@rules_toolchain//toolchain:resolved.bzl", _resolved = "export")

visibility("toolchain/echo/...")

DOC = _resolved.doc

ATTRS = _resolved.attrs

implementation = _resolved.implementation

resolved = _resolved.rule(
    toolchain = Label("//toolchain/echo:type"),
)
```

### Run

The `resolved` target allows the toolchain that is compatible with the current machine to be executed:

```py
bazelisk run -- //toolchain/echo:resolved "Hello, world!"
```

If the machine is compatible with the downloaded toolchain constraints, that will be used. Otherwise, it will fallback
to finding the toolchain on the local `PATH`.

[resolved]: https://github.com/bazelbuild/bazel/issues/14009