blob: e5d8d111a136f531d2ad51918a935ca9e7d55981 [file] [log] [blame]
// 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.skyframe;
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.ConfiguredRuleClassProvider;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.config.HostTransition;
import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
import com.google.devtools.build.lib.analysis.config.PackageProviderForConfigurations;
import com.google.devtools.build.lib.analysis.config.PatchTransition;
import com.google.devtools.build.lib.events.ErrorSensingEventHandler;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.RuleClassProvider;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyFunctionException;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
/**
* A builder for {@link ConfigurationCollectionValue} instances.
*
* @deprecated only used by static configurations, which are now permanently disabled
*/
@Deprecated
public class ConfigurationCollectionFunction implements SkyFunction {
private final RuleClassProvider ruleClassProvider;
public ConfigurationCollectionFunction(RuleClassProvider ruleClassProvider) {
this.ruleClassProvider = ruleClassProvider;
}
@Override
public SkyValue compute(SkyKey skyKey, Environment env) throws InterruptedException,
ConfigurationCollectionFunctionException {
throw new IllegalStateException("Dynamic configurations don't call this function and static "
+ "configurations have been removed");
}
/** Create the build configurations with the given options. */
private BuildConfigurationCollection getConfigurations(
Environment env,
PackageProviderForConfigurations loadedPackageProvider,
BuildOptions buildOptions,
ImmutableSet<String> multiCpu,
String repositoryName)
throws InvalidConfigurationException, InterruptedException {
// 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(
cache, env.getListener(), loadedPackageProvider, buildOptions, cpu, repositoryName);
if (targetConfiguration == null || targetConfigurations.contains(targetConfiguration)) {
continue;
}
targetConfigurations.add(targetConfiguration);
}
if (loadedPackageProvider.valuesMissing()) {
return null;
}
} else {
BuildConfiguration targetConfiguration = createConfiguration(
cache, env.getListener(), loadedPackageProvider, buildOptions, null, repositoryName);
if (targetConfiguration == null) {
return null;
}
targetConfigurations.add(targetConfiguration);
}
BuildConfiguration hostConfiguration = getHostConfiguration(env, targetConfigurations.get(0));
if (hostConfiguration == null) {
return null;
}
return new BuildConfigurationCollection(targetConfigurations, hostConfiguration);
}
/** Returns the host configuration, or null on missing Skyframe deps. */
private BuildConfiguration getHostConfiguration(
Environment env, BuildConfiguration targetConfiguration)
throws InvalidConfigurationException, InterruptedException {
if (targetConfiguration.useDynamicConfigurations()) {
BuildOptions targetOptions = targetConfiguration.getOptions();
// The host configuration builds from the data, not the target options. This is done
// so that host tools are always built without LIPO.
BuildOptions dataOptions = targetOptions;
Attribute.Transition dataTransition = targetConfiguration.getTransitions()
.getDynamicTransition(Attribute.ConfigurationTransition.DATA);
if (dataTransition != Attribute.ConfigurationTransition.NONE) {
dataOptions = ((PatchTransition) dataTransition).apply(targetOptions);
}
BuildOptions hostOptions =
targetOptions.get(BuildConfiguration.Options.class).useDistinctHostConfiguration
? HostTransition.INSTANCE.apply(dataOptions)
: dataOptions;
SkyKey hostConfigKey =
BuildConfigurationValue.key(
targetConfiguration.trimConfigurations()
? targetConfiguration.fragmentClasses()
: ((ConfiguredRuleClassProvider) ruleClassProvider).getAllFragments(),
hostOptions);
BuildConfigurationValue skyValHost = (BuildConfigurationValue)
env.getValueOrThrow(hostConfigKey, InvalidConfigurationException.class);
// Also preload the target configuration so the configured target functions for
// top-level targets don't have to waste cycles from a missing Skyframe dep.
SkyKey targetConfigKey =
BuildConfigurationValue.key(targetConfiguration.fragmentClasses(), targetOptions);
BuildConfigurationValue skyValTarget = (BuildConfigurationValue)
env.getValueOrThrow(targetConfigKey, InvalidConfigurationException.class);
if (skyValHost == null || skyValTarget == null) {
return null;
}
return skyValHost.getConfiguration();
} else {
return targetConfiguration.getConfiguration(Attribute.ConfigurationTransition.HOST);
}
}
@Nullable
private BuildConfiguration createConfiguration(
Cache<String, BuildConfiguration> cache,
ExtendedEventHandler originalEventListener,
PackageProviderForConfigurations loadedPackageProvider,
BuildOptions buildOptions,
String cpuOverride,
String repositoryName)
throws InvalidConfigurationException, InterruptedException {
ErrorSensingEventHandler eventHandler = new ErrorSensingEventHandler(originalEventListener);
if (cpuOverride != null) {
// TODO(bazel-team): Options classes should be immutable. This is a bit of a hack.
buildOptions = buildOptions.clone();
buildOptions.get(BuildConfiguration.Options.class).cpu = cpuOverride;
buildOptions.get(BuildConfiguration.Options.class).experimentalMultiCpuDistinguisher =
cpuOverride;
}
// Dead code: being removed. The original value used a class that's already been deleted.
BuildConfiguration targetConfig = null;
if (targetConfig == null) {
return null;
}
// The ConfigurationFactory may report an error rather than throwing an exception to support
// --keep_going. If so, we throw an error here.
if (eventHandler.hasErrors()) {
throw new InvalidConfigurationException("Build options are invalid");
}
return targetConfig;
}
@Override
public String extractTag(SkyKey skyKey) {
return null;
}
/**
* Used to declare all the exception types that can be wrapped in the exception thrown by
* {@link ConfigurationCollectionFunction#compute}.
*/
private static final class ConfigurationCollectionFunctionException extends
SkyFunctionException {
public ConfigurationCollectionFunctionException(InvalidConfigurationException e) {
super(e, Transience.PERSISTENT);
}
}
}