// Copyright 2014 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.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ListMultimap; import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe; import com.google.devtools.build.lib.packages.Attribute; 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.Rule; import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.util.Preconditions; import java.io.PrintStream; import java.io.Serializable; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; /** * The primary container for all main {@link BuildConfiguration} instances, * currently "target", "data", and "host". * *
The target configuration is used for all targets specified on the command * line. Data dependencies of targets in the target configuration use the data * configuration instead. * *
The host configuration is used for tools that are executed during the * build, e. g, compilers. * *
The "related" configurations are also contained in this class.
*/
@ThreadSafe
public final class BuildConfigurationCollection {
private final ImmutableList Don't use this method. It's limited in that it assumes a single host configuration for
* the entire collection. This may not be true in the future and more flexible interfaces based
* on dynamic configurations will likely supplant this interface anyway. Its main utility is
* to keep Bazel working while dynamic configuration progress is under way.
*/
public BuildConfiguration getHostConfiguration() {
return hostConfiguration;
}
/**
* Returns all configurations that can be reached from the target configuration through any kind
* of configuration transition.
*/
public Collection Only used for static configuration builds.
*
* @param configurationTransition the configuration transition
* @return the new configuration
*/
public BuildConfiguration getStaticConfiguration(Transition configurationTransition) {
Preconditions.checkState(!configuration.useDynamicConfigurations());
ConfigurationHolder holder = transitionTable.get(configurationTransition);
if (holder == null && configurationTransition.defaultsToSelf()) {
return configuration;
}
return holder.configuration;
}
/**
* Translates a static configuration {@link Transition} reference into the corresponding
* dynamic configuration transition.
*
* The difference is that with static configurations, the transition just models a desired
* type of transition that subsequently gets linked to a pre-built global configuration through
* custom logic in {@link BuildConfigurationCollection.Transitions} and
* {@link com.google.devtools.build.lib.analysis.ConfigurationCollectionFactory}.
*
* With dynamic configurations, the transition directly embeds the semantics, e.g.
* it includes not just a name but also the logic of how it should transform its input
* configuration.
*
* This is a connecting method meant to keep the two models in sync for the current time
* in which they must co-exist. Once dynamic configurations are production-ready, we'll remove
* the static configuration code entirely.
*/
protected Transition getDynamicTransition(Transition transition) {
Preconditions.checkState(configuration.useDynamicConfigurations());
if (transition == Attribute.ConfigurationTransition.NONE) {
return transition;
} else if (transition == Attribute.ConfigurationTransition.NULL) {
return transition;
} else if (transition == Attribute.ConfigurationTransition.HOST) {
return HostTransition.INSTANCE;
} else {
throw new UnsupportedOperationException("No dynamic mapping for " + transition.toString());
}
}
/**
* Arbitrary configuration transitions can be implemented by overriding this hook.
*/
@SuppressWarnings("unused")
public void configurationHook(Rule fromTarget, Attribute attribute, Target toTarget,
BuildConfiguration.TransitionApplier transitionApplier) {
}
/**
* Associating configurations to top-level targets can be implemented by overriding this hook.
*/
@SuppressWarnings("unused")
public BuildConfiguration toplevelConfigurationHook(Target toTarget) {
return configuration;
}
}
/**
* A holder class for {@link BuildConfiguration} instances that allows {@code null} values,
* because none of the Table implementations allow them.
*/
public static final class ConfigurationHolder implements Serializable {
private final BuildConfiguration configuration;
public ConfigurationHolder(BuildConfiguration configuration) {
this.configuration = configuration;
}
public BuildConfiguration getConfiguration() {
return configuration;
}
@Override
public int hashCode() {
return configuration == null ? 0 : configuration.hashCode();
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof ConfigurationHolder)) {
return false;
}
return Objects.equals(configuration, ((ConfigurationHolder) o).configuration);
}
}
}