From 19dda2577ece84e99f82af41c18a7bd2c796ff99 Mon Sep 17 00:00:00 2001 From: Cal Peyser Date: Wed, 11 Jan 2017 23:37:05 +0000 Subject: Allows a rule class to specify a configuration transtion that will apply to all incoming edges if dynamic configurations are turned on. This CL does not cover top-level nodes. -- PiperOrigin-RevId: 144258789 MOS_MIGRATED_REVID=144258789 --- .../lib/analysis/config/BuildConfiguration.java | 20 ++++++- .../analysis/config/ComposingSplitTransition.java | 66 ++++++++++++++++++++++ .../devtools/build/lib/packages/RuleClass.java | 35 ++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/google/devtools/build/lib/analysis/config/ComposingSplitTransition.java (limited to 'src/main/java/com/google') diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java index c80b2b463a..553c88c9db 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java @@ -14,6 +14,7 @@ package com.google.devtools.build.lib.analysis.config; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.base.Verify; @@ -46,6 +47,7 @@ import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.EventHandler; import com.google.devtools.build.lib.packages.AspectDescriptor; import com.google.devtools.build.lib.packages.Attribute; +import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition; import com.google.devtools.build.lib.packages.Attribute.Configurator; import com.google.devtools.build.lib.packages.Attribute.SplitTransition; import com.google.devtools.build.lib.packages.Attribute.Transition; @@ -1797,11 +1799,22 @@ public final class BuildConfiguration { } getCurrentTransitions().configurationHook(fromRule, attribute, toTarget, this); + Rule associatedRule = toTarget.getAssociatedRule(); + PatchTransition ruleClassTransition = (PatchTransition) + associatedRule.getRuleClassObject().getTransition(); + + if (ruleClassTransition != null) { + if (currentTransition == ConfigurationTransition.NONE) { + currentTransition = ruleClassTransition; + } else { + currentTransition = new ComposingSplitTransition(ruleClassTransition, currentTransition); + } + } + // We don't support rule class configurators (which might imply composed transitions). // The only current use of that is LIPO, which can't currently be invoked with dynamic // configurations (e.g. this code can never get called for LIPO builds). So check that // if there is a configurator, it's for LIPO, in which case we can ignore it. - Rule associatedRule = toTarget.getAssociatedRule(); if (associatedRule != null) { @SuppressWarnings("unchecked") RuleClass.Configurator func = @@ -2387,6 +2400,11 @@ public final class BuildConfiguration { return options.cpu; } + @VisibleForTesting + public String getHostCpu() { + return options.hostCpu; + } + public boolean runfilesEnabled() { switch (options.enableRunfiles) { case YES: diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/ComposingSplitTransition.java b/src/main/java/com/google/devtools/build/lib/analysis/config/ComposingSplitTransition.java new file mode 100644 index 0000000000..c4287d8ea9 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/analysis/config/ComposingSplitTransition.java @@ -0,0 +1,66 @@ +// Copyright 2017 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.analysis.config; + +import com.google.common.collect.ImmutableList; +import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition; +import com.google.devtools.build.lib.packages.Attribute.SplitTransition; +import com.google.devtools.build.lib.packages.Attribute.Transition; +import java.util.List; + +/** + * A split transition that combines a Transition with a {@link PatchTransition}. The patch is + * applied first, followed by the Transition. + * + *

We implement a {@link SplitTransition} here since that abstraction can capture all possible + * composed transitions - both those that produce multiple output configurations and those that + * do not. + */ +public class ComposingSplitTransition implements SplitTransition { + + private PatchTransition patch; + private Transition transition; + + /** + * Creates a {@link ComposingSplitTransition} with the given {@link Transition} and + * {@link PatchTransition}. + */ + public ComposingSplitTransition(PatchTransition patch, Transition transition) { + this.patch = patch; + this.transition = transition; + } + + @Override + public List split(BuildOptions buildOptions) { + BuildOptions patchedOptions = patch.apply(buildOptions); + if (transition == ConfigurationTransition.NONE) { + return ImmutableList.of(patchedOptions); + } else if (transition instanceof PatchTransition) { + return ImmutableList.of(((PatchTransition) transition).apply(patchedOptions)); + } else if (transition instanceof SplitTransition) { + return ((SplitTransition) transition).split(patchedOptions); + } else { + throw new IllegalStateException( + String.format("Unsupported composite transition type: %s", + transition.getClass().getName())); + } + } + + @Override + public boolean defaultsToSelf() { + return true; + } +} + diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java index b6b314bbcf..5bd4d83f60 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java +++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java @@ -36,6 +36,7 @@ import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.events.NullEventHandler; import com.google.devtools.build.lib.packages.Attribute.SkylarkComputedDefaultTemplate; import com.google.devtools.build.lib.packages.Attribute.SkylarkComputedDefaultTemplate.CannotPrecomputeDefaultsException; +import com.google.devtools.build.lib.packages.Attribute.Transition; import com.google.devtools.build.lib.packages.BuildType.SelectorList; import com.google.devtools.build.lib.packages.ConfigurationFragmentPolicy.MissingFragmentPolicy; import com.google.devtools.build.lib.packages.RuleFactory.AttributeValuesMap; @@ -473,6 +474,7 @@ public final class RuleClass { private boolean outputsDefaultExecutable = false; private ImplicitOutputsFunction implicitOutputsFunction = ImplicitOutputsFunction.NONE; private Configurator configurator = NO_CHANGE; + private Transition transition; private ConfiguredTargetFactory configuredTargetFactory = null; private PredicateWithMessage validityPredicate = PredicatesWithMessage.alwaysTrue(); @@ -586,6 +588,7 @@ public final class RuleClass { outputsDefaultExecutable, implicitOutputsFunction, configurator, + transition, configuredTargetFactory, validityPredicate, preferredDependencyPredicate, @@ -719,10 +722,28 @@ public final class RuleClass { public Builder cfg(Configurator configurator) { Preconditions.checkState(type != RuleClassType.ABSTRACT, "Setting not inherited property (cfg) of abstract rule class '%s'", name); + Preconditions.checkState(transition == null, + "Property cfg cannot be set to both a configurator and a transition"); this.configurator = configurator; return this; } + /** + * Applies the given transition to all incoming edges for this rule class. Does not work with + * static configurations. + * + *

Note that the given transition must be a PatchTransition instance. We use the more + * general Transtion here because PatchTransition is not available in this package. + */ + public Builder cfg(Transition transition) { + Preconditions.checkState(type != RuleClassType.ABSTRACT, + "Setting not inherited property (cfg) of abstract rule class '%s'", name); + Preconditions.checkState(configurator == NO_CHANGE, + "Property cfg cannot be set to both a configurator and a transition"); + this.transition = transition; + return this; + } + public Builder factory(ConfiguredTargetFactory factory) { this.configuredTargetFactory = factory; return this; @@ -982,6 +1003,14 @@ public final class RuleClass { */ private final Configurator configurator; + /** + * A configuration transition that should be applied on any edge of the configured target graph + * that leads into a target of this rule class. + * + *

This transition must be a PatchTransition, but that class is not accessible in this package. + */ + private final Transition transition; + /** * The factory that creates configured targets from this rule. */ @@ -1065,6 +1094,7 @@ public final class RuleClass { boolean outputsDefaultExecutable, ImplicitOutputsFunction implicitOutputsFunction, Configurator configurator, + Transition transition, ConfiguredTargetFactory configuredTargetFactory, PredicateWithMessage validityPredicate, Predicate preferredDependencyPredicate, @@ -1086,6 +1116,7 @@ public final class RuleClass { this.binaryOutput = binaryOutput; this.implicitOutputsFunction = implicitOutputsFunction; this.configurator = Preconditions.checkNotNull(configurator); + this.transition = transition; this.configuredTargetFactory = configuredTargetFactory; this.validityPredicate = validityPredicate; this.preferredDependencyPredicate = preferredDependencyPredicate; @@ -1155,6 +1186,10 @@ public final class RuleClass { return (Configurator) configurator; } + public Transition getTransition() { + return transition; + } + @SuppressWarnings("unchecked") public ConfiguredTargetFactory getConfiguredTargetFactory() { return (ConfiguredTargetFactory) configuredTargetFactory; -- cgit v1.2.3