use of com.google.devtools.build.lib.packages.Attribute.LateBoundDefault in project bazel by bazelbuild.
the class DependencyResolver method resolveLateBoundAttribute.
/**
* Returns the label dependencies for the given late-bound attribute in this rule.
*
* @param rule the rule being evaluated
* @param attribute the attribute to evaluate
* @param config the configuration to evaluate the attribute in
* @param attributeMap mapper to attribute values
*/
private Iterable<Label> resolveLateBoundAttribute(Rule rule, Attribute attribute, BuildConfiguration config, AttributeMap attributeMap) throws EvalException, InterruptedException {
Preconditions.checkArgument(attribute.isLateBound());
@SuppressWarnings("unchecked") LateBoundDefault<BuildConfiguration> lateBoundDefault = (LateBoundDefault<BuildConfiguration>) attribute.getLateBoundDefault();
// TODO(bazel-team): This might be too expensive - can we cache this somehow?
if (!lateBoundDefault.getRequiredConfigurationFragments().isEmpty()) {
if (!config.hasAllFragments(lateBoundDefault.getRequiredConfigurationFragments())) {
return ImmutableList.<Label>of();
}
}
// TODO(bazel-team): We should check if the implementation tries to access an undeclared
// fragment.
Object actualValue = lateBoundDefault.resolve(rule, attributeMap, config);
if (EvalUtils.isNullOrNone(actualValue)) {
return ImmutableList.<Label>of();
}
try {
ImmutableList.Builder<Label> deps = ImmutableList.builder();
if (attribute.getType() == BuildType.LABEL) {
deps.add(rule.getLabel().resolveRepositoryRelative(BuildType.LABEL.cast(actualValue)));
} else if (attribute.getType() == BuildType.LABEL_LIST) {
for (Label label : BuildType.LABEL_LIST.cast(actualValue)) {
deps.add(rule.getLabel().resolveRepositoryRelative(label));
}
} else {
throw new IllegalStateException(String.format("Late bound attribute '%s' is not a label or a label list", attribute.getName()));
}
return deps.build();
} catch (ClassCastException e) {
// From either of the cast calls above.
throw new EvalException(rule.getLocation(), String.format("When computing the default value of %s, expected '%s', got '%s'", attribute.getName(), attribute.getType(), EvalUtils.getDataTypeName(actualValue, true)));
}
}
use of com.google.devtools.build.lib.packages.Attribute.LateBoundDefault in project bazel by bazelbuild.
the class DependencyResolver method resolveLateBoundAttributes.
/**
* Resolves the dependencies for all late-bound attributes in this rule.
*
* <p>Late-bound attributes need special handling because they require configuration
* transitions to determine their values.
*
* <p>In other words, the normal process of dependency resolution is:
* <ol>
* <li>Find every label value in the rule's attributes</li>
* <li>Apply configuration transitions over each value to get its dep configuration
* <li>Return each value with its dep configuration</li>
* </ol>
*
* This doesn't work for late-bound attributes because you can't get their values without
* knowing the configuration first. And that configuration may not be the owning rule's
* configuration. Specifically, {@link LateBoundDefault#useHostConfiguration()} switches to the
* host config and late-bound split attributes branch into multiple split configs.
*
* <p>This method implements that logic and makes sure the normal configuration
* transition logic mixes with it cleanly.
*
* @param depResolver the resolver for this rule's deps
* @param ruleConfig the rule's configuration
* @param hostConfig the equivalent host configuration
*/
private void resolveLateBoundAttributes(RuleResolver depResolver, BuildConfiguration ruleConfig, BuildConfiguration hostConfig) throws EvalException, InvalidConfigurationException, InconsistentAspectOrderException, InterruptedException {
ConfiguredAttributeMapper attributeMap = depResolver.attributeMap;
for (AttributeAndOwner attributeAndOwner : depResolver.attributes) {
Attribute attribute = attributeAndOwner.attribute;
if (!attribute.isLateBound() || !attribute.getCondition().apply(attributeMap)) {
continue;
}
@SuppressWarnings("unchecked") LateBoundDefault<BuildConfiguration> lateBoundDefault = (LateBoundDefault<BuildConfiguration>) attribute.getLateBoundDefault();
Collection<BuildOptions> splitOptions = getSplitOptions(depResolver.rule, attribute, ruleConfig);
if (!splitOptions.isEmpty()) {
// Late-bound attribute with a split transition:
// Since we want to get the same results as BuildConfiguration.evaluateTransition (but
// skip it since we've already applied the split), we want to make sure this logic
// doesn't do anything differently. evaluateTransition has additional logic
// for host configs and attributes with configurators. So we check here that neither of
// of those apply, in the name of keeping the fork as simple as possible.
Verify.verify(attribute.getConfigurator() == null);
Verify.verify(!lateBoundDefault.useHostConfiguration());
Iterable<BuildConfiguration> splitConfigs;
if (!ruleConfig.useDynamicConfigurations()) {
splitConfigs = ruleConfig.getSplitConfigurations(attribute.getSplitTransition(depResolver.rule));
} else {
splitConfigs = getConfigurations(ruleConfig.fragmentClasses(), splitOptions);
if (splitConfigs == null) {
// Need Skyframe deps.
continue;
}
}
for (BuildConfiguration splitConfig : splitConfigs) {
for (Label dep : resolveLateBoundAttribute(depResolver.rule, attribute, splitConfig, attributeMap)) {
// Skip the normal config transition pipeline and directly feed the split config. This
// is because the split already had to be applied to determine the attribute's value.
// This makes the split logic in the normal pipeline redundant and potentially
// incorrect.
depResolver.resolveDep(attributeAndOwner, dep, splitConfig);
}
}
} else {
// Late-bound attribute without a split transition:
for (Label dep : resolveLateBoundAttribute(depResolver.rule, attribute, lateBoundDefault.useHostConfiguration() ? hostConfig : ruleConfig, attributeMap)) {
// Process this dep like a normal attribute.
depResolver.resolveDep(attributeAndOwner, dep);
}
}
}
}
Aggregations