aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/config
diff options
context:
space:
mode:
authorGravatar juliexxia <juliexxia@google.com>2017-09-20 23:53:15 +0200
committerGravatar László Csomor <laszlocsomor@google.com>2017-09-21 11:04:23 +0200
commit0e7051a55ab0396feeea7b6f9750594a02ef9c34 (patch)
tree356f27e43c9ba8381012fa3806431569a262e39a /src/main/java/com/google/devtools/build/lib/rules/config
parent4c3ef116e3aba72a0fc643b670e2cd872e85028d (diff)
Allow config_settings to match on constraint_values to a target_platform. This is on the way to making select() work with constraint_values re: #305.
PiperOrigin-RevId: 169454982
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/config')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/config/BUILD2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/config/ConfigSetting.java135
2 files changed, 126 insertions, 11 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/config/BUILD b/src/main/java/com/google/devtools/build/lib/rules/config/BUILD
index 414500922d..4f047852bc 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/config/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/rules/config/BUILD
@@ -21,6 +21,8 @@ java_library(
"//src/main/java/com/google/devtools/build/lib:preconditions",
"//src/main/java/com/google/devtools/build/lib:skylarkinterface",
"//src/main/java/com/google/devtools/build/lib/actions",
+ "//src/main/java/com/google/devtools/build/lib/analysis/platform",
+ "//src/main/java/com/google/devtools/build/lib/analysis/platform:utils",
"//src/main/java/com/google/devtools/build/lib/analysis/whitelisting",
"//src/main/java/com/google/devtools/build/lib/cmdline",
"//src/main/java/com/google/devtools/build/lib/collect",
diff --git a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigSetting.java b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigSetting.java
index 88d1283bd9..f4cc35eb78 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigSetting.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigSetting.java
@@ -39,6 +39,10 @@ import com.google.devtools.build.lib.analysis.config.BuildConfigurationOptionDet
import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
import com.google.devtools.build.lib.analysis.config.TransitiveOptionDetails;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.analysis.platform.ConstraintSettingInfo;
+import com.google.devtools.build.lib.analysis.platform.ConstraintValueInfo;
+import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
+import com.google.devtools.build.lib.analysis.platform.PlatformProviderUtils;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.AttributeMap;
import com.google.devtools.build.lib.packages.BuildType;
@@ -51,6 +55,7 @@ import com.google.devtools.common.options.OptionsBase;
import com.google.devtools.common.options.OptionsParser;
import com.google.devtools.common.options.OptionsParsingException;
import java.util.Collection;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -91,25 +96,37 @@ public class ConfigSetting implements RuleConfiguredTargetFactory {
ruleContext.getPrerequisites(
ConfigSettingRule.FLAG_SETTINGS_ATTRIBUTE, Mode.TARGET);
- if (nativeFlagSettings.size() == 0 && userDefinedFlagSettings.isEmpty()) {
- ruleContext.ruleError(
- String.format(
- "Either %s or %s must be specified and non-empty",
- ConfigSettingRule.SETTINGS_ATTRIBUTE,
- ConfigSettingRule.FLAG_SETTINGS_ATTRIBUTE));
+ // Get the constraint values that match this rule
+ Iterable<ConstraintValueInfo> constraintValues =
+ PlatformProviderUtils.constraintValues(
+ ruleContext.getPrerequisites(
+ ConfigSettingRule.CONSTRAINT_VALUES_ATTRIBUTE, Mode.DONT_CHECK));
+
+ // Get the target platform
+ Iterable<PlatformInfo> targetPlatforms =
+ PlatformProviderUtils.platforms(
+ ruleContext.getPrerequisites(
+ ConfigSettingRule.TARGET_PLATFORMS_ATTRIBUTE, Mode.DONT_CHECK));
+
+ // Check that this config_setting contains at least one of {values, define_values,
+ // constraint_values}
+ if (!checkValidConditions(
+ nativeFlagSettings, userDefinedFlagSettings, constraintValues, ruleContext)) {
return null;
}
- ConfigFeatureFlagMatch featureFlags =
- ConfigFeatureFlagMatch.fromAttributeValueAndPrerequisites(
- userDefinedFlagSettings, flagValues, ruleContext);
-
boolean nativeFlagsMatch =
matchesConfig(
nativeFlagSettings.entries(),
BuildConfigurationOptionDetails.get(ruleContext.getConfiguration()),
ruleContext);
+ ConfigFeatureFlagMatch featureFlags =
+ ConfigFeatureFlagMatch.fromAttributeValueAndPrerequisites(
+ userDefinedFlagSettings, flagValues, ruleContext);
+
+ boolean constraintValuesMatch = matchesConstraints(constraintValues, targetPlatforms);
+
if (ruleContext.hasErrors()) {
return null;
}
@@ -119,7 +136,7 @@ public class ConfigSetting implements RuleConfiguredTargetFactory {
ruleContext.getLabel(),
nativeFlagSettings,
featureFlags.getSpecifiedFlagValues(),
- nativeFlagsMatch && featureFlags.matches());
+ nativeFlagsMatch && featureFlags.matches() && constraintValuesMatch);
return new RuleConfiguredTargetBuilder(ruleContext)
.addProvider(RunfilesProvider.class, RunfilesProvider.EMPTY)
@@ -130,11 +147,79 @@ public class ConfigSetting implements RuleConfiguredTargetFactory {
.build();
}
+ private boolean checkValidConditions(
+ ImmutableMultimap<String, String> nativeFlagSettings,
+ Map<Label, String> userDefinedFlagSettings,
+ Iterable<ConstraintValueInfo> constraintValues,
+ RuleErrorConsumer errors) {
+ // Check to make sure this config_setting contains and sets least one of {values, define_values,
+ // flag_value or constraint_values}.
+ if (!valuesAreSet(nativeFlagSettings, userDefinedFlagSettings, constraintValues, errors)) {
+ return false;
+ }
+
+ // The set of constraint_values in a config_setting should never contain multiple
+ // constraint_values that map to the same constraint_setting. This checks if there are
+ // duplicates and records an error if so.
+ if (containsDuplicateSettings(constraintValues, errors)) {
+ return false;
+ }
+
+ return true;
+ }
+
/**
* User error when value settings can't be properly parsed.
*/
private static final String PARSE_ERROR_MESSAGE = "error while parsing configuration settings: ";
+ private boolean valuesAreSet(
+ ImmutableMultimap<String, String> nativeFlagSettings,
+ Map<Label, String> userDefinedFlagSettings,
+ Iterable<ConstraintValueInfo> constraintValues,
+ RuleErrorConsumer errors) {
+ if (nativeFlagSettings.isEmpty()
+ && userDefinedFlagSettings.isEmpty()
+ && Iterables.isEmpty(constraintValues)) {
+ errors.ruleError(
+ String.format(
+ "Either %s, %s or %s must be specified and non-empty",
+ ConfigSettingRule.SETTINGS_ATTRIBUTE,
+ ConfigSettingRule.FLAG_SETTINGS_ATTRIBUTE,
+ ConfigSettingRule.CONSTRAINT_VALUES_ATTRIBUTE));
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * The set of constraint_values in a config_setting should never contain multiple
+ * constraint_values that map to the same constraint_setting. This method checks if there are
+ * duplicates and records an error if so.
+ */
+ private boolean containsDuplicateSettings(
+ Iterable<ConstraintValueInfo> constraintValues, RuleErrorConsumer errors) {
+ HashMap<ConstraintSettingInfo, ConstraintValueInfo> constraints = new HashMap<>();
+ for (ConstraintValueInfo constraint : constraintValues) {
+ ConstraintSettingInfo setting = constraint.constraint();
+ if (constraints.containsKey(setting)) {
+ errors.attributeError(
+ ConfigSettingRule.TARGET_PLATFORMS_ATTRIBUTE,
+ String.format(
+ PARSE_ERROR_MESSAGE
+ + "the target platform contains multiple values '%s' "
+ + "and '%s' that map to the same setting '%s'",
+ constraint.label(),
+ constraints.get(setting).label(),
+ setting.label()));
+ return true;
+ }
+ constraints.put(setting, constraint);
+ }
+ return false;
+ }
+
/**
* Given a list of [flagName, flagValue] pairs for native Blaze flags, returns true if
* flagName == flagValue for every item in the list under this configuration, false otherwise.
@@ -244,6 +329,33 @@ public class ConfigSetting implements RuleConfiguredTargetFactory {
return actualList.contains(expectedSingleValue);
}
+ private boolean matchesConstraints(
+ Iterable<ConstraintValueInfo> expected, Iterable<PlatformInfo> targetPlatforms) {
+ // config_setting didn't specify any constraint values
+ if (Iterables.isEmpty(expected)) {
+ return true;
+ }
+
+ // TODO(jcater): re-evaluate this for multiple target platforms.
+ PlatformInfo targetPlatform = Iterables.getOnlyElement(targetPlatforms);
+ // config_setting DID specify constraint_value(s) but no target platforms are set
+ // in the configuration.
+ if (Iterables.isEmpty(targetPlatform.constraints())) {
+ return false;
+ }
+
+ // For every constraint in the attr check if it is (1)set aka non-null and
+ // (2)set correctly in the platform.
+ for (ConstraintValueInfo constraint : expected) {
+ ConstraintSettingInfo setting = constraint.constraint();
+ ConstraintValueInfo targetValue = targetPlatform.getConstraint(setting);
+ if (targetValue == null || !constraint.equals(targetValue)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private static final class ConfigFeatureFlagMatch {
private final boolean matches;
private final ImmutableMap<Label, String> specifiedFlagValues;
@@ -338,3 +450,4 @@ public class ConfigSetting implements RuleConfiguredTargetFactory {
}
}
}
+