// Copyright 2015 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.rules.cpp; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.ActionConfig; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.CollidingProvidesException; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.CrosstoolSelectable; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Feature; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Queue; import java.util.Set; /** * Implements the feature selection algorithm. * *
Feature selection is done by first enabling all features reachable by an 'implies' edge, and
* then iteratively pruning features that have unmet requirements.
*/
class FeatureSelection {
/**
* The selectables Bazel would like to enable; either because they are supported and generally
* useful, or because the user required them (for example through the command line).
*/
private final ImmutableSet We guarantee the command line to be in the order in which the flags were specified in the
* configuration.
*/
private final ImmutableList This will be used to determine which selectables need to be re-checked after a selectable
* was disabled.
*/
private final ImmutableMultimap If it is not, remove the selectable from the set of enabled selectables, and re-check all
* selectables that may now also become disabled.
*/
private void checkActivatable(CrosstoolSelectable selectable) {
if (!enabled.contains(selectable) || isSatisfied(selectable)) {
return;
}
enabled.remove(selectable);
// Once we disable a selectable, we have to re-check all selectables that can be affected
// by that removal.
// 1. A selectable that implied the current selectable is now going to be disabled.
for (CrosstoolSelectable impliesCurrent : impliedBy.get(selectable)) {
checkActivatable(impliesCurrent);
}
// 2. A selectable that required the current selectable may now be disabled, depending on
// whether the requirement was optional.
for (CrosstoolSelectable requiresCurrent : requiredBy.get(selectable)) {
checkActivatable(requiresCurrent);
}
// 3. A selectable that this selectable implied may now be disabled if no other selectables
// also implies it.
for (CrosstoolSelectable implied : implies.get(selectable)) {
checkActivatable(implied);
}
}
/**
* @return whether all requirements of the selectable are met in the set of currently enabled
* selectables.
*/
private boolean isSatisfied(CrosstoolSelectable selectable) {
return (requestedSelectables.contains(selectable) || isImpliedByEnabledActivatable(selectable))
&& allImplicationsEnabled(selectable)
&& allRequirementsMet(selectable);
}
/** @return whether a currently enabled selectable implies the given selectable. */
private boolean isImpliedByEnabledActivatable(CrosstoolSelectable selectable) {
return !Collections.disjoint(impliedBy.get(selectable), enabled);
}
/** @return whether all implications of the given feature are enabled. */
private boolean allImplicationsEnabled(CrosstoolSelectable selectable) {
for (CrosstoolSelectable implied : implies.get(selectable)) {
if (!enabled.contains(implied)) {
return false;
}
}
return true;
}
/**
* @return whether all requirements are enabled.
* This implies that for any of the selectable sets all of the specified selectable are
* enabled.
*/
private boolean allRequirementsMet(CrosstoolSelectable feature) {
if (!requires.containsKey(feature)) {
return true;
}
for (ImmutableSet
*
*/
private final ImmutableMultimap