bazelbuild / bazelbuild/bazel

No way to use toolchains correctly in executable rule output

Open
#19,645 44 comments 7 reactions 0 assignees View on GitHub
P3 team-Configurability type: feature request
Dominant language
Java
Stars
25.8k
Forks
4.6k
Avg merge
2d 20h
Merged PRs (30d)
72

Description

### Description of the feature request:

A common pattern[^1] I see in rules is toolchain declarations that effectively capture a tool _path_, and templated executable/test rules that resolve the toolchain and substitute the tool path into the executable file output.

Unfortunately this is incorrect! When the exec and target platforms differ, the toolchain will be resolved for the _exec_ platform, but the executable/test output needs to be for the _target_ platform.

As far as I can see, there is no way to make toolchain resolution / platform transitions do the correct thing here. Since executable rules are how bazel tests work, this is a pretty major gap in the toolchains/platforms story. I can't file bugs against rules, because there is no reasonable solution to suggest. This is a feature request for a solution that is (a) correct, and also ideally (b) easy/obvious.

One onerous current workaround is to declare _two_ toolchains for all such cases. One that uses exec_compatible_with/target_compatible_with as usual, and is used when the toolchain is invoked by an action directly. And a second toolchain that uses target_compatible_with _only_, which can be used in executable rule output. This is moderately terrible, since this duplicates work for everybody, confuses the meaning of exec_compatible_with vs target_compatible_with, and toolchain authors can't anticipate when their toolchain needs to be used in this way - undoing the loose coupling between author and consumer that is kind of the point of toolchains.

An incorrect (afaics) version of the two-toolchains approach is to _only_ declare target_compatible_with toolchain, then create a "current_foo_toolchain" rule that resolves the toolchain for a particular target, and returns the toolchain provider through a rule attribute - see eg [python toolchain](https://github.com/bazelbuild/rules_python/blob/main/docs/python.md#current_py_toolchain). This is incorrect in general because another toolchain that depends on this toolchain cannot be resolved at the same time for the same exec+target combination (ie: `toolchains=[foo]` with a dependency on another rule with `toolchains=[bar]`, is not the same as `toolchains=[foo, bar]`).

As a possible implementation, I'd _love_ to be able to do `exec_group(cfg='target')`, since I think `ctx.exec_groups["target"].toolchains` is an intuitive and 'obvious' way to address the above.

Another option is to _not_ use toolchains for what are effectively artifacts. Rule authors obviously like the loose coupling between toolchain declaration and use however, so this potential path would require widespread advocacy/documentation, and perhaps a canonical meta-library for an "artifact toolchain".

See also slack thread: https://bazelbuild.slack.com/archives/CA31HN1T3/p1690176577746239

[^1]: Examples of (incorrect) toolchains used for executable rules in [rules_js](https://github.com/aspect-build/rules_js/issues/1168), [rules_docker](https://github.com/bazelbuild/rules_docker/blob/8e70c6bcb584a15a8fd061ea489b933c0ff344ca/contrib/push-all.bzl#L56), [rules_oci](https://github.com/bazel-contrib/rules_oci/blob/54d04c20c6bfa0aa1089385e5abe35af462f0bd7/oci/private/push.bzl#L102-L103), [gazelle](https://github.com/bazelbuild/bazel-gazelle/blob/c11d7ce0133088d69e5a18541f219490cc3c1996/def.bzl#L93)

### Which category does this issue belong to?

Core

### What underlying problem are you trying to solve with this feature?

It should be possible to resolve and refer to the correct toolchain for an executable rule output.

### Which operating system are you running Bazel on?

macos and Linux

### What is the output of `bazel info release`?

6.3.2

### If `bazel info release` returns `development version` or `(@non-git)`, tell us how you built Bazel.

_No response_

### What's the output of `git remote get-url origin; git rev-parse master; git rev-parse HEAD` ?

_No response_

### Have you found anything relevant by searching the web?

_No response_

### Any other information, logs, or outputs that you want to share?

_No response_

Contributor guide

Open the contributing guide

Research direction

Start with executable rules, toolchain resolution, exec groups, and the proposed ctx.exec_groups["target"].toolchains entry point. Compare the linked rules_js, rules_docker, rules_oci, and Gazelle examples with the current two-toolchain workaround. Done means executable outputs resolve the toolchain for the target platform without duplicated declarations, while preserving correct exec-platform resolution.

Written by the indexing model from the issue text.

Assessment

Domain
build-system
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.