Repository: bazelbuild/bazel
Issue: Support for execution-only "bootstrap" toolchains
Labels: type: feature request
team-Configurability

### Description of the problem / feature request:

I'd like to be able to define toolchains that only target the execution platform. This would be useful for bootstrap toolchains that build tools that run on the execution platform and are used in other toolchains.

### Feature requests: what underlying problem are you trying to solve with this feature?

In rules_go, we're building a pluggable static analysis framework. Users will define a `go_checker` rule, which depends on `go_library` rules that implement custom checks. The `go_checker` rule does some code generation and produces a binary for the execution platform. A specific `go_checker` binary is registered in WORKSPACE. This `go_checker` binary should ideally be part of the toolchain for the target platform and should run on all the source files compiled using that toolchain.

The problem is a cyclic dependency: the Go toolchain should contain a `go_checker`, but we need a toolchain to build a `go_checker`, since it depends on regular `go_library` rules. Ideally, we would be able to select an execution-only bootstrap toolchain that doesn't include the `go_checker`, and `go_library` rules would only use `go_checker` if it were available in the toolchain.

Currently, we're working around this by using a special rule, `go_tool_library` that does not depend on `go_checker`. `go_library` has an implicit dependency on `go_checker` (`go_checker` is not currently part of the toolchain).


Issue comments:
cc @katre
I think the only way to handle this will be to use two toolchain types: one for the bootstrapping, one for actual usage. If you write the implementation functions modularly, and use the same property names on the toolchain providers, you should be able to re-use a lot of code.

I'm closing this issue because I don't think this is something Bazel can support at this time.

Pull request review comments:

Patch that resolved the issue:
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java b/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java
index 0ae17e2093b747..b2b56b9b3ada08 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java
@@ -236,7 +236,8 @@ private void visitRule(
 
     Attribute toolchainsAttribute =
         attributeMap.getAttributeDefinition(PlatformSemantics.RESOLVED_TOOLCHAINS_ATTR);
-    resolveToolchainDependencies(outgoingEdges.get(toolchainsAttribute), toolchainLabels);
+    resolveToolchainDependencies(
+        outgoingEdges.get(toolchainsAttribute), toolchainLabels, ruleConfig);
   }
 
   /**
@@ -447,11 +448,10 @@ private void resolveLateBoundAttributes(
   }
 
   private void resolveToolchainDependencies(
-      Set<Dependency> dependencies, ImmutableSet<Label> toolchainLabels) {
+      Set<Dependency> dependencies, ImmutableSet<Label> toolchainLabels,
+      BuildConfiguration ruleConfig) {
     for (Label label : toolchainLabels) {
-      Dependency dependency =
-          Dependency.withTransitionAndAspects(
-              label, HostTransition.INSTANCE, AspectCollection.EMPTY);
+      Dependency dependency = Dependency.withConfiguration(label, ruleConfig);
       dependencies.add(dependency);
     }
   }


Test patch:
diff --git a/src/test/shell/bazel/toolchain_test.sh b/src/test/shell/bazel/toolchain_test.sh
index 097e874641ca60..12b22f892e26f5 100755
--- a/src/test/shell/bazel/toolchain_test.sh
+++ b/src/test/shell/bazel/toolchain_test.sh
@@ -168,6 +168,25 @@ EOF
   expect_log 'extra_str = "bar"'
 }
 
+function test_toolchain_build_with_target_configuration {
+  write_test_toolchain
+  write_test_rule
+  write_register_toolchain
+
+  mkdir -p demo
+  cat >> demo/BUILD <<EOF
+load('//toolchain:rule_use_toolchain.bzl', 'use_toolchain')
+# Use the toolchain.
+use_toolchain(
+    name = 'use',
+    message = 'this is the rule')
+EOF
+
+  bazel cquery 'kind("test_toolchain", deps(//demo:use))' | grep -Fv HOST \
+    &> $TEST_log || fail "cquery failed"
+  expect_log "//:test_toolchain_impl_1"
+}
+
 function test_toolchain_use_in_rule {
   write_test_toolchain
   write_test_rule