Add a undocumented way to define a platform that is autodetected from
the host.

Also add a single instance of that platform for standard usage.

Change-Id: I0e7a8eb3a44099076540c8d955fc0c0c70447583
PiperOrigin-RevId: 153878880
diff --git a/src/main/java/com/google/devtools/build/lib/rules/platform/Platform.java b/src/main/java/com/google/devtools/build/lib/rules/platform/Platform.java
index c396605..d1c48e9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/platform/Platform.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/platform/Platform.java
@@ -24,6 +24,8 @@
 import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.rules.platform.PlatformInfo.DuplicateConstraintException;
 import com.google.devtools.build.lib.syntax.Type;
+import com.google.devtools.build.lib.util.CPU;
+import com.google.devtools.build.lib.util.OS;
 import java.util.Map;
 
 /** Defines a platform for execution contexts. */
@@ -32,12 +34,16 @@
   public ConfiguredTarget create(RuleContext ruleContext)
       throws InterruptedException, RuleErrorException {
 
-    Iterable<ConstraintValueInfo> constraintValues =
-        ConstraintValueInfo.fromTargets(
-            ruleContext.getPrerequisites(PlatformRule.CONSTRAINT_VALUES_ATTR, Mode.DONT_CHECK));
-
     PlatformInfo.Builder platformBuilder = PlatformInfo.builder();
-    platformBuilder.addConstraints(constraintValues);
+
+    if (ruleContext.attributes().get(PlatformRule.HOST_PLATFORM_ATTR, Type.BOOLEAN)) {
+      // Create default constraints based on the current OS and CPU values.
+      autodetectHostConstraints(ruleContext, platformBuilder);
+    } else {
+      platformBuilder.addConstraints(
+          ConstraintValueInfo.fromTargets(
+              ruleContext.getPrerequisites(PlatformRule.CONSTRAINT_VALUES_ATTR, Mode.DONT_CHECK)));
+    }
 
     Map<String, String> remoteExecutionProperties =
         ruleContext.attributes().get(PlatformRule.REMOTE_EXECUTION_PROPS_ATTR, Type.STRING_DICT);
@@ -59,4 +65,32 @@
         .addNativeDeclaredProvider(platformInfo)
         .build();
   }
+
+  private void autodetectHostConstraints(
+      RuleContext ruleContext, PlatformInfo.Builder platformBuilder) {
+
+    // Add the CPU.
+    CPU cpu = CPU.getCurrent();
+    Iterable<ConstraintValueInfo> cpuConstraintValues =
+        ConstraintValueInfo.fromTargets(
+            ruleContext.getPrerequisites(PlatformRule.HOST_CPU_CONSTRAINTS_ATTR, Mode.DONT_CHECK));
+    for (ConstraintValueInfo constraint : cpuConstraintValues) {
+      if (cpu.getCanonicalName().equals(constraint.label().getName())) {
+        platformBuilder.addConstraint(constraint);
+        break;
+      }
+    }
+
+    // Add the OS.
+    OS os = OS.getCurrent();
+    Iterable<ConstraintValueInfo> osConstraintValues =
+        ConstraintValueInfo.fromTargets(
+            ruleContext.getPrerequisites(PlatformRule.HOST_OS_CONSTRAINTS_ATTR, Mode.DONT_CHECK));
+    for (ConstraintValueInfo constraint : osConstraintValues) {
+      if (os.getCanonicalName().equals(constraint.label().getName())) {
+        platformBuilder.addConstraint(constraint);
+        break;
+      }
+    }
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/platform/PlatformRule.java b/src/main/java/com/google/devtools/build/lib/rules/platform/PlatformRule.java
index cd33243..126cd9d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/platform/PlatformRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/platform/PlatformRule.java
@@ -30,6 +30,9 @@
   public static final String RULE_NAME = "platform";
   public static final String CONSTRAINT_VALUES_ATTR = "constraint_values";
   public static final String REMOTE_EXECUTION_PROPS_ATTR = "remote_execution_properties";
+  static final String HOST_PLATFORM_ATTR = "host_platform";
+  static final String HOST_CPU_CONSTRAINTS_ATTR = "host_cpu_constraints";
+  static final String HOST_OS_CONSTRAINTS_ATTR = "host_os_constraints";
 
   @Override
   public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) {
@@ -41,11 +44,37 @@
                 // No need to show up in ":all", etc. target patterns.
                 .value(ImmutableList.of("manual"))
                 .nonconfigurable("low-level attribute, used in platform configuration"))
+        /* <!-- #BLAZE_RULE(platform).ATTRIBUTE(constraint_values) -->
+        The constraint_values that define this platform.
+        <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
         .add(
             attr(CONSTRAINT_VALUES_ATTR, BuildType.LABEL_LIST)
                 .allowedFileTypes(FileTypeSet.NO_FILE)
                 .mandatoryProviders(ImmutableList.of(ConstraintValueInfo.SKYLARK_IDENTIFIER)))
+
+        /* <!-- #BLAZE_RULE(platform).ATTRIBUTE(remote_execution_properties) -->
+        A key/value dict of values that will be sent to a remote execution platform.
+        <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
         .add(attr(REMOTE_EXECUTION_PROPS_ATTR, Type.STRING_DICT))
+
+        // Undocumented. Indicates that this platform should auto-configure the platform constraints
+        // based on the current OS and CPU settings.
+        .add(
+            attr(HOST_PLATFORM_ATTR, Type.BOOLEAN)
+                .value(false)
+                .undocumented("Should only be used by internal packages."))
+        // Undocumented. Indicates to the rule which constraint_values to use for host CPU mapping.
+        .add(
+            attr(HOST_CPU_CONSTRAINTS_ATTR, BuildType.LABEL_LIST)
+                .allowedFileTypes(FileTypeSet.NO_FILE)
+                .mandatoryProviders(ImmutableList.of(ConstraintValueInfo.SKYLARK_IDENTIFIER))
+                .undocumented("Should only be used by internal packages."))
+        // Undocumented. Indicates to the rule which constraint_values to use for host OS mapping.
+        .add(
+            attr(HOST_OS_CONSTRAINTS_ATTR, BuildType.LABEL_LIST)
+                .allowedFileTypes(FileTypeSet.NO_FILE)
+                .mandatoryProviders(ImmutableList.of(ConstraintValueInfo.SKYLARK_IDENTIFIER))
+                .undocumented("Should only be used by internal packages."))
         .removeAttribute("deps")
         .removeAttribute("data")
         .exemptFromConstraintChecking("this rule is part of constraint definition")
diff --git a/src/test/java/com/google/devtools/build/lib/rules/platform/BUILD b/src/test/java/com/google/devtools/build/lib/rules/platform/BUILD
index 82e48b0..39b1617 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/platform/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/rules/platform/BUILD
@@ -10,7 +10,9 @@
     test_class = "com.google.devtools.build.lib.AllTests",
     deps = [
         "//src/main/java/com/google/devtools/build/lib:build-base",
+        "//src/main/java/com/google/devtools/build/lib:os_util",
         "//src/main/java/com/google/devtools/build/lib:syntax",
+        "//src/main/java/com/google/devtools/build/lib:util",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/rules/platform",
         "//src/test/java/com/google/devtools/build/lib:analysis_testutil",
diff --git a/src/test/java/com/google/devtools/build/lib/rules/platform/PlatformTest.java b/src/test/java/com/google/devtools/build/lib/rules/platform/PlatformTest.java
index d07fe4d..5cb0991 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/platform/PlatformTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/platform/PlatformTest.java
@@ -22,6 +22,8 @@
 import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.rules.platform.PlatformInfo.DuplicateConstraintException;
+import com.google.devtools.build.lib.util.CPU;
+import com.google.devtools.build.lib.util.OS;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -66,6 +68,39 @@
   }
 
   @Test
+  public void testPlatform_host() throws Exception {
+    String currentCpu = CPU.getCurrent().getCanonicalName();
+    String currentOs = OS.getCurrent().getCanonicalName();
+    scratch.file(
+        "host/BUILD",
+        "constraint_setting(name = 'cpu')",
+        "constraint_value(name = '" + currentCpu + "', constraint_setting = ':cpu')",
+        "constraint_value(name = 'another_cpu', constraint_setting = ':cpu')",
+        "constraint_setting(name = 'os')",
+        "constraint_value(name = '" + currentOs + "', constraint_setting = ':os')",
+        "constraint_value(name = 'another_os', constraint_setting = ':os')",
+        "platform(name = 'host_platform',",
+        "    host_platform = True,",
+        "    host_cpu_constraints = [':" + currentCpu + "', ':another_cpu'],",
+        "    host_os_constraints = [':" + currentOs + "', ':another_os'],",
+        ")");
+
+    ConfiguredTarget platform = getConfiguredTarget("//host:host_platform");
+    assertThat(platform).isNotNull();
+
+    PlatformInfo provider = PlatformInfo.fromTarget(platform);
+    assertThat(provider).isNotNull();
+
+    // Check the CPU and OS.
+    ConstraintSettingInfo cpuConstraint = ConstraintSettingInfo.create(makeLabel("//host:cpu"));
+    ConstraintSettingInfo osConstraint = ConstraintSettingInfo.create(makeLabel("//host:os"));
+    assertThat(provider.constraints())
+        .containsExactly(
+            ConstraintValueInfo.create(cpuConstraint, makeLabel("//host:" + currentCpu)),
+            ConstraintValueInfo.create(osConstraint, makeLabel("//host:" + currentOs)));
+  }
+
+  @Test
   public void testPlatform_overlappingConstraintValueError() throws Exception {
     checkError(
         "constraint/overlap",