-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
When the existing `--transitions` flag is set to a non-None value, cquery will report the configuration its dependencies are configured in. This allows for pruning away values from ruleInputs which are not required in the current configuration. Example output from running: `bazel cquery --transitions=lite --output=jsonproto 'deps(...)'`: ``` [...] "ruleInput": ["@bazel_tools//src/conditions:host_windows", "@bazel_tools//src/tools/launcher:launcher", "@bazel_tools//tools/launcher:launcher_windows"], "configuredRuleInput": [{ "label": "@bazel_tools//src/tools/launcher:launcher", "configurationChecksum": "01ec5513a9fc41b2a15570123817f3c2200ad9aeb21b1181d588a4b4f91d5693", "configurationId": 3 }] [...] ``` Previously on a non-Windows platform it was not possible to determine that the two windows-specific ruleInputs are not actually required - now we can see from the configuredRuleInput section that the windows-specific dependencies have been pruned by selection, and we can see that a transition has re-configured the ruleInput into the exec configuration. For dependencies which were not subject to transition (e.g. because they're in a non-transition attribute), or which had no configuration (e.g. because they're a source file), we add the label as a ConfiguredRuleInput _without_ any configuration information. This indicates that the dependency has not been pruned, but that the caller should determine the correct configuration from context (probably be determining whether it's a source file, and if so, considering it un-configured, otherwise propagating the contextual ConfiguredTarget's configuration). Fixes #14610 Fixes #14617 Implementation-wise, this took roughly the following shape: 1. Extract TransitionResolver from being inline in TransitionsOutputFormatterCallback 2. Extract KnownTargetsDependencyResolver from TransitionsOutputFormatterCallback.FormatterDependencyResolver 3. Conditionally call these from ProtoOutputFormatterCallback depending on the --transitions flag. Closes #15038. PiperOrigin-RevId: 445923176
- Loading branch information
1 parent
394ddb8
commit 9994c32
Showing
7 changed files
with
367 additions
and
94 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
186 changes: 186 additions & 0 deletions
186
src/main/java/com/google/devtools/build/lib/query2/cquery/CqueryTransitionResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
// Copyright 2022 The Bazel Authors. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
package com.google.devtools.build.lib.query2.cquery; | ||
|
||
import com.google.auto.value.AutoValue; | ||
import com.google.common.collect.ImmutableCollection; | ||
import com.google.common.collect.ImmutableList; | ||
import com.google.common.collect.ImmutableMap; | ||
import com.google.common.collect.ImmutableSet; | ||
import com.google.devtools.build.lib.analysis.DependencyKey; | ||
import com.google.devtools.build.lib.analysis.DependencyKind; | ||
import com.google.devtools.build.lib.analysis.DependencyKind.ToolchainDependencyKind; | ||
import com.google.devtools.build.lib.analysis.DependencyResolver; | ||
import com.google.devtools.build.lib.analysis.InconsistentAspectOrderException; | ||
import com.google.devtools.build.lib.analysis.TargetAndConfiguration; | ||
import com.google.devtools.build.lib.analysis.ToolchainCollection; | ||
import com.google.devtools.build.lib.analysis.ToolchainContext; | ||
import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; | ||
import com.google.devtools.build.lib.analysis.config.BuildOptions; | ||
import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider; | ||
import com.google.devtools.build.lib.analysis.config.transitions.NoTransition; | ||
import com.google.devtools.build.lib.analysis.config.transitions.NullTransition; | ||
import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory; | ||
import com.google.devtools.build.lib.analysis.config.transitions.TransitionUtil; | ||
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget; | ||
import com.google.devtools.build.lib.cmdline.Label; | ||
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; | ||
import com.google.devtools.build.lib.events.ExtendedEventHandler; | ||
import com.google.devtools.build.lib.packages.RuleTransitionData; | ||
import com.google.devtools.build.lib.packages.Target; | ||
import com.google.devtools.build.lib.util.OrderedSetMultimap; | ||
import java.util.Map; | ||
import javax.annotation.Nullable; | ||
|
||
/** | ||
* TransitionResolver resolves the dependencies of a ConfiguredTarget, reporting which | ||
* configurations its dependencies are actually needed in according to the transitions applied to | ||
* them. This class has been extracted from TransitionsOutputFormatterCallback.java so that it can | ||
* be used in both ProtoOutputFormatterCallback and TransitionsOutputFormatterCallback | ||
*/ | ||
public class CqueryTransitionResolver { | ||
|
||
/** | ||
* ResolvedTransition represents a single edge in the dependency graph, between some target and a | ||
* target it depends on, reachable via a single attribute. | ||
*/ | ||
@AutoValue | ||
@Immutable | ||
public abstract static class ResolvedTransition { | ||
|
||
static ResolvedTransition create( | ||
Label label, | ||
ImmutableCollection<BuildOptions> buildOptions, | ||
String attributeName, | ||
String transitionName) { | ||
return new AutoValue_CqueryTransitionResolver_ResolvedTransition( | ||
label, buildOptions, attributeName, transitionName); | ||
} | ||
|
||
/** The label of the target being depended on. */ | ||
abstract Label label(); | ||
|
||
/** | ||
* The configuration(s) this edge results in. This is a collection because a split transition | ||
* may lead to a single attribute requesting a dependency in multiple configurations. | ||
* | ||
* <p>If a target is depended on via two attributes, separate ResolvedTransitions should be | ||
* used, rather than combining the two into a single ResolvedTransition with multiple options. | ||
* | ||
* <p>If no transition was applied to an attribute, this collection will be empty. | ||
*/ | ||
abstract ImmutableCollection<BuildOptions> options(); | ||
|
||
/** The name of the attribute via which the dependency was requested. */ | ||
abstract String attributeName(); | ||
|
||
/** The name of the transition applied to the attribute. */ | ||
abstract String transitionName(); | ||
} | ||
|
||
private final ExtendedEventHandler eventHandler; | ||
private final DependencyResolver dependencyResolver; | ||
private final ConfiguredTargetAccessor accessor; | ||
private final CqueryThreadsafeCallback cqueryThreadsafeCallback; | ||
@Nullable private final TransitionFactory<RuleTransitionData> trimmingTransitionFactory; | ||
|
||
public CqueryTransitionResolver( | ||
ExtendedEventHandler eventHandler, | ||
DependencyResolver dependencyResolver, | ||
ConfiguredTargetAccessor accessor, | ||
CqueryThreadsafeCallback cqueryThreadsafeCallback, | ||
@Nullable TransitionFactory<RuleTransitionData> trimmingTransitionFactory) { | ||
this.eventHandler = eventHandler; | ||
this.dependencyResolver = dependencyResolver; | ||
this.accessor = accessor; | ||
this.cqueryThreadsafeCallback = cqueryThreadsafeCallback; | ||
this.trimmingTransitionFactory = trimmingTransitionFactory; | ||
} | ||
|
||
/** | ||
* Return the set of dependencies of a KeyedConfiguredTarget, including information about the | ||
* configuration transitions applied to the dependencies. | ||
* | ||
* @see ResolvedTransition for more details. | ||
* @param keyedConfiguredTarget the configured target whose dependencies are being looked up. | ||
*/ | ||
public ImmutableSet<ResolvedTransition> dependencies(KeyedConfiguredTarget keyedConfiguredTarget) | ||
throws DependencyResolver.Failure, InconsistentAspectOrderException, InterruptedException { | ||
ImmutableSet.Builder<ResolvedTransition> resolved = new ImmutableSet.Builder<>(); | ||
|
||
if (!(keyedConfiguredTarget.getConfiguredTarget() instanceof RuleConfiguredTarget)) { | ||
return resolved.build(); | ||
} | ||
|
||
Target target = accessor.getTarget(keyedConfiguredTarget); | ||
BuildConfigurationValue config = | ||
cqueryThreadsafeCallback.getConfiguration(keyedConfiguredTarget.getConfigurationKey()); | ||
|
||
ImmutableMap<Label, ConfigMatchingProvider> configConditions = | ||
keyedConfiguredTarget.getConfigConditions(); | ||
|
||
// Get a ToolchainContext to use for dependency resolution. | ||
ToolchainCollection<ToolchainContext> toolchainContexts = | ||
accessor.getToolchainContexts(target, config); | ||
// We don't actually use fromOptions in our implementation of | ||
// DependencyResolver but passing to avoid passing a null and since we have the information | ||
// anyway. | ||
OrderedSetMultimap<DependencyKind, DependencyKey> deps = | ||
dependencyResolver.dependentNodeMap( | ||
new TargetAndConfiguration(target, config), | ||
/*aspect=*/ null, | ||
configConditions, | ||
toolchainContexts, | ||
trimmingTransitionFactory); | ||
for (Map.Entry<DependencyKind, DependencyKey> attributeAndDep : deps.entries()) { | ||
DependencyKey dep = attributeAndDep.getValue(); | ||
|
||
String dependencyName; | ||
if (DependencyKind.isToolchain(attributeAndDep.getKey())) { | ||
ToolchainDependencyKind tdk = (ToolchainDependencyKind) attributeAndDep.getKey(); | ||
if (tdk.isDefaultExecGroup()) { | ||
dependencyName = "[toolchain dependency]"; | ||
} else { | ||
dependencyName = String.format("[toolchain dependency: %s]", tdk.getExecGroupName()); | ||
} | ||
} else { | ||
dependencyName = attributeAndDep.getKey().getAttribute().getName(); | ||
} | ||
|
||
if (attributeAndDep.getValue().getTransition() == NoTransition.INSTANCE | ||
|| attributeAndDep.getValue().getTransition() == NullTransition.INSTANCE) { | ||
resolved.add( | ||
ResolvedTransition.create( | ||
dep.getLabel(), | ||
ImmutableList.of(), | ||
dependencyName, | ||
attributeAndDep.getValue().getTransition().getName())); | ||
continue; | ||
} | ||
BuildOptions fromOptions = config.getOptions(); | ||
// TODO(bazel-team): support transitions on Starlark-defined build flags. These require | ||
// Skyframe loading to get flag default values. See ConfigurationResolver.applyTransition | ||
// for an example of the required logic. | ||
ImmutableSet<BuildOptions> toOptions = | ||
ImmutableSet.copyOf( | ||
dep.getTransition() | ||
.apply(TransitionUtil.restrict(dep.getTransition(), fromOptions), eventHandler) | ||
.values()); | ||
resolved.add( | ||
ResolvedTransition.create( | ||
dep.getLabel(), toOptions, dependencyName, dep.getTransition().getName())); | ||
} | ||
return resolved.build(); | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
...main/java/com/google/devtools/build/lib/query2/cquery/KnownTargetsDependencyResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// Copyright 2022 The Bazel Authors. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
package com.google.devtools.build.lib.query2.cquery; | ||
|
||
import static com.google.common.collect.ImmutableMap.toImmutableMap; | ||
|
||
import com.google.common.collect.ImmutableMap; | ||
import com.google.devtools.build.lib.analysis.DependencyKind; | ||
import com.google.devtools.build.lib.analysis.DependencyResolver; | ||
import com.google.devtools.build.lib.analysis.TargetAndConfiguration; | ||
import com.google.devtools.build.lib.causes.Cause; | ||
import com.google.devtools.build.lib.cmdline.Label; | ||
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; | ||
import com.google.devtools.build.lib.packages.Target; | ||
import com.google.devtools.build.lib.util.OrderedSetMultimap; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.function.Function; | ||
|
||
/** | ||
* KnownTargetsDependencyResolver is a DependencyResolver which resolves statically over a known set | ||
* of targets. It can be useful when performing queries over a known pre-resolved universe of | ||
* targets. This class has been extracted from TransitionsOutputFormatterCallback.java so that it | ||
* can be used in both ProtoOutputFormatterCallback and TransitionsOutputFormatterCallback | ||
*/ | ||
public class KnownTargetsDependencyResolver extends DependencyResolver { | ||
|
||
private final ImmutableMap<Label, Target> knownTargets; | ||
|
||
public KnownTargetsDependencyResolver(Map<Label, Target> knownTargets) { | ||
this.knownTargets = ImmutableMap.copyOf(knownTargets); | ||
} | ||
|
||
@Override | ||
protected Map<Label, Target> getTargets( | ||
OrderedSetMultimap<DependencyKind, Label> labelMap, | ||
TargetAndConfiguration fromNode, | ||
NestedSetBuilder<Cause> rootCauses) { | ||
return labelMap.values().stream() | ||
.distinct() | ||
.filter(Objects::nonNull) | ||
.filter(knownTargets::containsKey) | ||
.collect(toImmutableMap(Function.identity(), knownTargets::get)); | ||
} | ||
} |
Oops, something went wrong.