aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools
diff options
context:
space:
mode:
authorGravatar Lukacs Berki <lberki@google.com>2015-06-29 07:28:44 +0000
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2015-06-29 16:39:26 +0000
commit4313d37941a4c8196af112e9bf3b22d6c366d3cc (patch)
tree2633a8eccbba7b0420d93b37b82d140fea5d104d /src/main/java/com/google/devtools
parentca763a66230e84671c1f8c277d3d0fdb425d3149 (diff)
Make split configuration transitions work with Bazel.
Creating the split configurations in Bazel uncovered an incrementality issue: ConfigurationFactory.hostConfigCache kept state between builds untracked by Skyframe, which is not good, and therefore had to be fixed. -- MOS_MIGRATED_REVID=97106917
Diffstat (limited to 'src/main/java/com/google/devtools')
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/ConfigurationCollectionFactory.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java3
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationFactory.java41
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelConfigurationCollection.java60
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationCollectionFunction.java20
6 files changed, 75 insertions, 54 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfigurationCollectionFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfigurationCollectionFactory.java
index 4ce7426433..14bb2a9695 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfigurationCollectionFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfigurationCollectionFactory.java
@@ -13,6 +13,7 @@
// limitations under the License.
package com.google.devtools.build.lib.analysis;
+import com.google.common.cache.Cache;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.config.ConfigurationFactory;
@@ -32,6 +33,8 @@ public interface ConfigurationCollectionFactory {
* <p>Also it may create a set of BuildConfigurations and define a transition table over them.
* All configurations during a build should be accessible from this top-level configuration
* via configuration transitions.
+ * @param configurationFactory the configuration factory
+ * @param cache a cache for BuildConfigurations
* @param loadedPackageProvider the package provider
* @param buildOptions top-level build options representing the command-line
* @param errorEventListener the event listener for errors
@@ -43,6 +46,7 @@ public interface ConfigurationCollectionFactory {
@Nullable
BuildConfiguration createConfigurations(
ConfigurationFactory configurationFactory,
+ Cache<String, BuildConfiguration> cache,
PackageProviderForConfigurations loadedPackageProvider,
BuildOptions buildOptions,
EventHandler errorEventListener,
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
index b81ea289b5..b1598f6748 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
@@ -209,8 +209,7 @@ public final class RuleContext extends TargetContext
}
/**
- * Returns the host configuration for this rule; keep in mind that there may be multiple different
- * host configurations, even during a single build.
+ * Returns the host configuration for this rule.
*/
public BuildConfiguration getHostConfiguration() {
return hostConfiguration;
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 7a2e1ad619..ecd96136ff 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
@@ -1152,7 +1152,6 @@ public final class BuildConfiguration implements Serializable {
}
public Transitions getTransitions() {
- Preconditions.checkState(this.transitions != null || isHostConfiguration());
return transitions;
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationFactory.java
index e623bdf38d..4ae2349c21 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationFactory.java
@@ -17,7 +17,6 @@ package com.google.devtools.build.lib.analysis.config;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
@@ -39,7 +38,7 @@ import javax.annotation.Nullable;
* and should be simplified in the future, if
* possible. Right now, creating a {@link BuildConfiguration} instance involves
* creating the instance itself and the related configurations; the main method
- * is {@link #createConfiguration}.
+ * is {@link #createConfigurations}.
*
* <p>Avoid calling into this class, and instead use the skyframe infrastructure to obtain
* configuration instances.
@@ -51,11 +50,6 @@ import javax.annotation.Nullable;
public final class ConfigurationFactory {
private final List<ConfigurationFragmentFactory> configurationFragmentFactories;
private final ConfigurationCollectionFactory configurationCollectionFactory;
-
- // A cache of key to configuration instances.
- private final Cache<String, BuildConfiguration> hostConfigCache =
- CacheBuilder.newBuilder().softValues().build();
-
private boolean performSanityCheck = true;
public ConfigurationFactory(
@@ -77,37 +71,30 @@ public final class ConfigurationFactory {
performSanityCheck = false;
}
- /** Create the build configurations with the given options. */
+ /** Creates a set of build configurations with top-level configuration having the given options.
+ *
+ * <p>The rest of the configurations are created based on the set of transitions available.
+ */
@Nullable
- public BuildConfiguration createConfiguration(
+ public BuildConfiguration createConfigurations(
+ Cache<String, BuildConfiguration> cache,
PackageProviderForConfigurations loadedPackageProvider, BuildOptions buildOptions,
EventHandler errorEventListener)
throws InvalidConfigurationException {
- return configurationCollectionFactory.createConfigurations(this,
+ return configurationCollectionFactory.createConfigurations(this, cache,
loadedPackageProvider, buildOptions, errorEventListener, performSanityCheck);
}
/**
- * Returns a (possibly new) canonical host BuildConfiguration instance based
- * upon a given request configuration
- */
- @Nullable
- public BuildConfiguration getHostConfiguration(
- PackageProviderForConfigurations loadedPackageProvider,
- BuildOptions buildOptions, boolean fallback) throws InvalidConfigurationException {
- return getConfiguration(loadedPackageProvider, buildOptions.createHostOptions(fallback),
- false, hostConfigCache);
- }
-
- /**
- * The core of BuildConfiguration creation. All host and target instances are
- * constructed and cached here.
+ * Returns a {@link com.google.devtools.build.lib.analysis.config.BuildConfiguration} based on
+ * the given set of build options.
+ *
+ * <p>If the configuration has already been created, re-uses it, otherwise, creates a new one.
*/
@Nullable
public BuildConfiguration getConfiguration(PackageProviderForConfigurations loadedPackageProvider,
- BuildOptions buildOptions,
- boolean actionsDisabled, Cache<String, BuildConfiguration> cache)
- throws InvalidConfigurationException {
+ BuildOptions buildOptions, boolean actionsDisabled, Cache<String, BuildConfiguration> cache)
+ throws InvalidConfigurationException {
Map<Class<? extends Fragment>, Fragment> fragments = new HashMap<>();
// Create configuration fragments
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelConfigurationCollection.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelConfigurationCollection.java
index 47689efa0d..d6dd55e262 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelConfigurationCollection.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelConfigurationCollection.java
@@ -15,9 +15,10 @@
package com.google.devtools.build.lib.bazel.rules;
import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
+import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashBasedTable;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ListMultimap;
import com.google.common.collect.Table;
import com.google.devtools.build.lib.analysis.ConfigurationCollectionFactory;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
@@ -32,6 +33,7 @@ import com.google.devtools.build.lib.bazel.rules.cpp.BazelCppRuleClasses.CppTran
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.packages.AggregatingAttributeMapper;
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 com.google.devtools.build.lib.packages.NoSuchThingException;
import com.google.devtools.build.lib.packages.Rule;
@@ -41,6 +43,7 @@ import com.google.devtools.build.lib.syntax.Label;
import java.util.Collection;
import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -55,18 +58,11 @@ public class BazelConfigurationCollection implements ConfigurationCollectionFact
@Nullable
public BuildConfiguration createConfigurations(
ConfigurationFactory configurationFactory,
+ Cache<String, BuildConfiguration> cache,
PackageProviderForConfigurations loadedPackageProvider,
BuildOptions buildOptions,
EventHandler errorEventListener,
boolean performSanityCheck) throws InvalidConfigurationException {
-
- // We cache all the related configurations for this target configuration in a cache that is
- // dropped at the end of this method call. We instead rely on the cache for entire collections
- // for caching the target and related configurations, and on a dedicated host configuration
- // cache for the host configuration.
- Cache<String, BuildConfiguration> cache =
- CacheBuilder.newBuilder().<String, BuildConfiguration>build();
-
// Target configuration
BuildConfiguration targetConfiguration = configurationFactory.getConfiguration(
loadedPackageProvider, buildOptions, false, cache);
@@ -80,11 +76,26 @@ public class BazelConfigurationCollection implements ConfigurationCollectionFact
// Note that this passes in the dataConfiguration, not the target
// configuration. This is intentional.
BuildConfiguration hostConfiguration = getHostConfigurationFromRequest(configurationFactory,
- loadedPackageProvider, dataConfiguration, buildOptions);
+ loadedPackageProvider, dataConfiguration, buildOptions, cache);
if (hostConfiguration == null) {
return null;
}
+ ListMultimap<SplitTransition<?>, BuildConfiguration> splitTransitionsTable =
+ ArrayListMultimap.create();
+ for (SplitTransition<BuildOptions> transition : buildOptions.getPotentialSplitTransitions()) {
+ List<BuildOptions> splitOptionsList = transition.split(buildOptions);
+ for (BuildOptions splitOptions : splitOptionsList) {
+ BuildConfiguration splitConfig = configurationFactory.getConfiguration(
+ loadedPackageProvider, splitOptions, false, cache);
+ splitTransitionsTable.put(transition, splitConfig);
+ }
+ }
+ if (loadedPackageProvider.valuesMissing()) {
+ return null;
+ }
+
+
// Sanity check that the implicit labels are all in the transitive closure of explicit ones.
// This also registers all targets in the cache entry and validates them on subsequent requests.
Set<Label> reachableLabels = new HashSet<>();
@@ -104,7 +115,7 @@ public class BazelConfigurationCollection implements ConfigurationCollectionFact
}
BuildConfiguration result = setupTransitions(
- targetConfiguration, dataConfiguration, hostConfiguration);
+ targetConfiguration, dataConfiguration, hostConfiguration, splitTransitionsTable);
result.reportInvalidOptions(errorEventListener);
return result;
}
@@ -130,14 +141,15 @@ public class BazelConfigurationCollection implements ConfigurationCollectionFact
private BuildConfiguration getHostConfigurationFromRequest(
ConfigurationFactory configurationFactory,
PackageProviderForConfigurations loadedPackageProvider,
- BuildConfiguration requestConfig, BuildOptions buildOptions)
+ BuildConfiguration requestConfig, BuildOptions buildOptions,
+ Cache<String, BuildConfiguration> cache)
throws InvalidConfigurationException {
BuildConfiguration.Options commonOptions = buildOptions.get(BuildConfiguration.Options.class);
if (!commonOptions.useDistinctHostConfiguration) {
return requestConfig;
} else {
- BuildConfiguration hostConfig = configurationFactory.getHostConfiguration(
- loadedPackageProvider, buildOptions, /*fallback=*/false);
+ BuildConfiguration hostConfig = configurationFactory.getConfiguration(
+ loadedPackageProvider, buildOptions.createHostOptions(false), false, cache);
if (hostConfig == null) {
return null;
}
@@ -146,9 +158,13 @@ public class BazelConfigurationCollection implements ConfigurationCollectionFact
}
static BuildConfiguration setupTransitions(BuildConfiguration targetConfiguration,
- BuildConfiguration dataConfiguration, BuildConfiguration hostConfiguration) {
- Set<BuildConfiguration> allConfigurations = ImmutableSet.of(targetConfiguration,
- dataConfiguration, hostConfiguration);
+ BuildConfiguration dataConfiguration, BuildConfiguration hostConfiguration,
+ ListMultimap<SplitTransition<?>, BuildConfiguration> splitTransitionsTable) {
+ Set<BuildConfiguration> allConfigurations = new LinkedHashSet<>();
+ allConfigurations.add(targetConfiguration);
+ allConfigurations.add(dataConfiguration);
+ allConfigurations.add(hostConfiguration);
+ allConfigurations.addAll(splitTransitionsTable.values());
Table<BuildConfiguration, Transition, ConfigurationHolder> transitionBuilder =
HashBasedTable.create();
@@ -177,7 +193,13 @@ public class BazelConfigurationCollection implements ConfigurationCollectionFact
for (BuildConfiguration config : allConfigurations) {
Transitions outgoingTransitions =
- new BuildConfigurationCollection.Transitions(config, transitionBuilder.row(config));
+ new BuildConfigurationCollection.Transitions(config, transitionBuilder.row(config),
+ // Split transitions must not have their own split transitions because then they
+ // would be applied twice due to a quirk in DependencyResolver. See the comment in
+ // DependencyResolver.resolveLateBoundAttributes().
+ splitTransitionsTable.values().contains(config)
+ ? ImmutableListMultimap.<SplitTransition<?>, BuildConfiguration>of()
+ : splitTransitionsTable);
// We allow host configurations to be shared between target configurations. In that case, the
// transitions may already be set.
// TODO(bazel-team): Check that the transitions are identical, or even better, change the
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationCollectionFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationCollectionFunction.java
index 7d2efe8214..3131868943 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationCollectionFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationCollectionFunction.java
@@ -15,6 +15,8 @@ package com.google.devtools.build.lib.skyframe;
import com.google.common.base.Supplier;
import com.google.common.base.Verify;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
@@ -86,11 +88,18 @@ public class ConfigurationCollectionFunction implements SkyFunction {
PackageProviderForConfigurations loadedPackageProvider, BuildOptions buildOptions,
ImmutableSet<String> multiCpu)
throws InvalidConfigurationException {
+ // We cache all the related configurations for this target configuration in a cache that is
+ // dropped at the end of this method call. We instead rely on the cache for entire collections
+ // for caching the target and related configurations, and on a dedicated host configuration
+ // cache for the host configuration.
+ Cache<String, BuildConfiguration> cache =
+ CacheBuilder.newBuilder().<String, BuildConfiguration>build();
List<BuildConfiguration> targetConfigurations = new ArrayList<>();
+
if (!multiCpu.isEmpty()) {
for (String cpu : multiCpu) {
BuildConfiguration targetConfiguration = createConfiguration(
- eventHandler, loadedPackageProvider, buildOptions, cpu);
+ cache, eventHandler, loadedPackageProvider, buildOptions, cpu);
if (targetConfiguration == null || targetConfigurations.contains(targetConfiguration)) {
continue;
}
@@ -101,7 +110,7 @@ public class ConfigurationCollectionFunction implements SkyFunction {
}
} else {
BuildConfiguration targetConfiguration = createConfiguration(
- eventHandler, loadedPackageProvider, buildOptions, null);
+ cache, eventHandler, loadedPackageProvider, buildOptions, null);
if (targetConfiguration == null) {
return null;
}
@@ -122,7 +131,8 @@ public class ConfigurationCollectionFunction implements SkyFunction {
}
@Nullable
- public BuildConfiguration createConfiguration(
+ private BuildConfiguration createConfiguration(
+ Cache<String, BuildConfiguration> cache,
EventHandler originalEventListener,
PackageProviderForConfigurations loadedPackageProvider,
BuildOptions buildOptions, String cpuOverride) throws InvalidConfigurationException {
@@ -133,8 +143,8 @@ public class ConfigurationCollectionFunction implements SkyFunction {
buildOptions.get(BuildConfiguration.Options.class).cpu = cpuOverride;
}
- BuildConfiguration targetConfig = configurationFactory.get().createConfiguration(
- loadedPackageProvider, buildOptions, errorEventListener);
+ BuildConfiguration targetConfig = configurationFactory.get().createConfigurations(
+ cache, loadedPackageProvider, buildOptions, errorEventListener);
if (targetConfig == null) {
return null;
}