Add a new toolchain type for c++.  In order to do this, PlatformConfiguration is made a legal configuration fragment for every rule class.

Add a default "dummy" c++ toolchain to prevent resolution errors when legacy toolchain selection logic is used.  Add toolchain mocks to java and shell tests.

PiperOrigin-RevId: 166854893
diff --git a/src/create_embedded_tools.py b/src/create_embedded_tools.py
index 699edd0..668db21 100644
--- a/src/create_embedded_tools.py
+++ b/src/create_embedded_tools.py
@@ -29,8 +29,8 @@
 
 output_paths = [
     ('*tools/jdk/BUILD*', lambda x: 'tools/jdk/BUILD'),
-    ('*tools/platforms/platforms.BUILD', lambda x: 'platforms/BUILD'),
-    ('*tools/platforms/*', lambda x: 'platforms/' + os.path.basename(x)),
+    ('*tools/platforms/platforms.BUILD', lambda x: 'tools/platforms/BUILD'),
+    ('*tools/platforms/*', lambda x: 'tools/platforms/' + os.path.basename(x)),
     ('*JavaBuilder*_deploy.jar', lambda x: 'tools/jdk/' + os.path.basename(x)),
     ('*JacocoCoverage*_deploy.jar',
      lambda x: 'tools/jdk/JacocoCoverage_deploy.jar'),
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java b/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
index 817f4d1..f52d66f 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
@@ -182,41 +182,60 @@
    * Share common attributes across both base and Skylark base rules.
    */
   public static RuleClass.Builder commonCoreAndSkylarkAttributes(RuleClass.Builder builder) {
-    return builder
+    return PlatformSemantics.platformAttributes(builder)
         // The visibility attribute is special: it is a nodep label, and loading the
         // necessary package groups is handled by {@link LabelVisitor#visitTargetVisibility}.
         // Package groups always have the null configuration so that they are not duplicated
         // needlessly.
-        .add(attr("visibility", NODEP_LABEL_LIST).orderIndependent().cfg(HOST)
-            .nonconfigurable("special attribute integrated more deeply into Bazel's core logic"))
-        .add(attr("deprecation", STRING).value(deprecationDefault)
-            .nonconfigurable("Used in core loading phase logic with no access to configs"))
-        .add(attr("tags", STRING_LIST).orderIndependent().taggable()
-            .nonconfigurable("low-level attribute, used in TargetUtils without configurations"))
-        .add(attr("generator_name", STRING).undocumented("internal")
-            .nonconfigurable("static structure of a rule"))
-        .add(attr("generator_function", STRING).undocumented("internal")
-            .nonconfigurable("static structure of a rule"))
-        .add(attr("generator_location", STRING).undocumented("internal")
-            .nonconfigurable("static structure of a rule"))
-        .add(attr("testonly", BOOLEAN).value(testonlyDefault)
-            .nonconfigurable("policy decision: rules testability should be consistent"))
+        .add(
+            attr("visibility", NODEP_LABEL_LIST)
+                .orderIndependent()
+                .cfg(HOST)
+                .nonconfigurable(
+                    "special attribute integrated more deeply into Bazel's core logic"))
+        .add(
+            attr("deprecation", STRING)
+                .value(deprecationDefault)
+                .nonconfigurable("Used in core loading phase logic with no access to configs"))
+        .add(
+            attr("tags", STRING_LIST)
+                .orderIndependent()
+                .taggable()
+                .nonconfigurable("low-level attribute, used in TargetUtils without configurations"))
+        .add(
+            attr("generator_name", STRING)
+                .undocumented("internal")
+                .nonconfigurable("static structure of a rule"))
+        .add(
+            attr("generator_function", STRING)
+                .undocumented("internal")
+                .nonconfigurable("static structure of a rule"))
+        .add(
+            attr("generator_location", STRING)
+                .undocumented("internal")
+                .nonconfigurable("static structure of a rule"))
+        .add(
+            attr("testonly", BOOLEAN)
+                .value(testonlyDefault)
+                .nonconfigurable("policy decision: rules testability should be consistent"))
         .add(attr("features", STRING_LIST).orderIndependent())
         .add(attr(":action_listener", LABEL_LIST).cfg(HOST).value(ACTION_LISTENER))
-        .add(attr(RuleClass.COMPATIBLE_ENVIRONMENT_ATTR, LABEL_LIST)
-            .allowedRuleClasses(EnvironmentRule.RULE_NAME)
-            .cfg(Attribute.ConfigurationTransition.HOST)
-            .allowedFileTypes(FileTypeSet.NO_FILE)
-            .dontCheckConstraints()
-            .nonconfigurable("special logic for constraints and select: see ConstraintSemantics")
-        )
-        .add(attr(RuleClass.RESTRICTED_ENVIRONMENT_ATTR, LABEL_LIST)
-            .allowedRuleClasses(EnvironmentRule.RULE_NAME)
-            .cfg(Attribute.ConfigurationTransition.HOST)
-            .allowedFileTypes(FileTypeSet.NO_FILE)
-            .dontCheckConstraints()
-            .nonconfigurable("special logic for constraints and select: see ConstraintSemantics")
-        );
+        .add(
+            attr(RuleClass.COMPATIBLE_ENVIRONMENT_ATTR, LABEL_LIST)
+                .allowedRuleClasses(EnvironmentRule.RULE_NAME)
+                .cfg(Attribute.ConfigurationTransition.HOST)
+                .allowedFileTypes(FileTypeSet.NO_FILE)
+                .dontCheckConstraints()
+                .nonconfigurable(
+                    "special logic for constraints and select: see ConstraintSemantics"))
+        .add(
+            attr(RuleClass.RESTRICTED_ENVIRONMENT_ATTR, LABEL_LIST)
+                .allowedRuleClasses(EnvironmentRule.RULE_NAME)
+                .cfg(Attribute.ConfigurationTransition.HOST)
+                .allowedFileTypes(FileTypeSet.NO_FILE)
+                .dontCheckConstraints()
+                .nonconfigurable(
+                    "special logic for constraints and select: see ConstraintSemantics"));
   }
 
   public static RuleClass.Builder nameAttribute(RuleClass.Builder builder) {
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/PlatformOptions.java b/src/main/java/com/google/devtools/build/lib/analysis/PlatformOptions.java
index 3376e96..dd65946 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/PlatformOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/PlatformOptions.java
@@ -36,7 +36,7 @@
   @Option(
     name = "experimental_host_platform",
     converter = BuildConfiguration.LabelConverter.class,
-    defaultValue = "@bazel_tools//platforms:host_platform",
+    defaultValue = "@bazel_tools//tools/platforms:host_platform",
     documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
     effectTags = {OptionEffectTag.UNKNOWN},
     metadataTags = {OptionMetadataTag.HIDDEN},
@@ -49,7 +49,7 @@
   @Option(
     name = "experimental_platforms",
     converter = BuildConfiguration.LabelListConverter.class,
-    defaultValue = "@bazel_tools//platforms:target_platform",
+    defaultValue = "@bazel_tools//tools/platforms:target_platform",
     documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
     effectTags = {OptionEffectTag.UNKNOWN},
     metadataTags = {OptionMetadataTag.HIDDEN},
@@ -60,7 +60,7 @@
   @Option(
     name = "extra_toolchains",
     converter = LabelListConverter.class,
-    defaultValue = "",
+    defaultValue = "@bazel_tools//tools/cpp:dummy_cc_toolchain",
     documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
     effectTags = {OptionEffectTag.UNKNOWN},
     metadataTags = {OptionMetadataTag.HIDDEN},
@@ -98,6 +98,8 @@
   public PlatformOptions getHost(boolean fallback) {
     PlatformOptions host = (PlatformOptions) getDefault();
     host.platforms = ImmutableList.of(this.hostPlatform);
+    host.hostPlatform = this.hostPlatform;
+    host.extraToolchains = this.extraToolchains;
     return host;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java b/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java
index d93c5a6..45c967e 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java
@@ -26,6 +26,7 @@
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.packages.RuleClass;
 import java.util.List;
+import javax.annotation.Nullable;
 
 /** Helper class to manage rules' use of platforms. */
 public class PlatformSemantics {
@@ -40,19 +41,22 @@
         @Override
         public List<Label> resolve(
             Rule rule, AttributeMap attributes, BuildConfiguration configuration) {
-          if (rule.getRuleClassObject().getRequiredToolchains().isEmpty()) {
-            return null;
+          // rule may be null for tests
+          if (rule == null || rule.getRuleClassObject().getRequiredToolchains().isEmpty()) {
+            return ImmutableList.of();
           }
           return configuration.getFragment(PlatformConfiguration.class).getTargetPlatforms();
         }
       };
 
   /** Implementation for the :execution_platform attribute. */
+  @Nullable
   public static final Attribute.LateBoundLabel<BuildConfiguration> EXECUTION_PLATFORM =
       new Attribute.LateBoundLabel<BuildConfiguration>(PlatformConfiguration.class) {
         @Override
         public Label resolve(Rule rule, AttributeMap attributes, BuildConfiguration configuration) {
-          if (rule.getRuleClassObject().getRequiredToolchains().isEmpty()) {
+          // rule may be null for tests
+          if (rule == null || rule.getRuleClassObject().getRequiredToolchains().isEmpty()) {
             return null;
           }
           return configuration.getFragment(PlatformConfiguration.class).getExecutionPlatform();
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java b/src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java
index 9cbdd47..16a29fd 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java
@@ -142,6 +142,8 @@
         prerequisiteMap
             .keys()
             .stream()
+            // Keys in prerequisiteMap can be null, see {@link DependencyResolver#dependentNodeMap}.
+            .filter(attribute -> attribute != null)
             .filter(attribute -> attribute.getName().equals(PlatformSemantics.TOOLCHAINS_ATTR))
             .findFirst();
     Preconditions.checkState(
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
index 3e850d9..6c84873 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
@@ -39,7 +39,6 @@
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
 import com.google.devtools.build.lib.analysis.DefaultInfo;
 import com.google.devtools.build.lib.analysis.OutputGroupProvider;
-import com.google.devtools.build.lib.analysis.PlatformSemantics;
 import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
 import com.google.devtools.build.lib.analysis.skylark.SkylarkAttr.Descriptor;
 import com.google.devtools.build.lib.analysis.test.TestConfiguration;
@@ -129,10 +128,9 @@
   /** Parent rule class for non-executable non-test Skylark rules. */
   public static final RuleClass baseRule =
       BaseRuleClasses.commonCoreAndSkylarkAttributes(
-              PlatformSemantics.platformAttributes(
-                  BaseRuleClasses.nameAttribute(
-                          new RuleClass.Builder("$base_rule", RuleClassType.ABSTRACT, true))
-                      .add(attr("expect_failure", STRING))))
+              BaseRuleClasses.nameAttribute(
+                      new RuleClass.Builder("$base_rule", RuleClassType.ABSTRACT, true))
+                  .add(attr("expect_failure", STRING)))
           .build();
 
   /** Parent rule class for executable non-test Skylark rules. */
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
index 2b4666a..dba1338 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
@@ -57,6 +57,7 @@
 import com.google.devtools.build.lib.rules.cpp.CcToolchain;
 import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
 import com.google.devtools.build.lib.rules.cpp.CppFileTypes;
+import com.google.devtools.build.lib.rules.cpp.CppHelper;
 import com.google.devtools.build.lib.rules.cpp.CppRuleClasses;
 import com.google.devtools.build.lib.rules.cpp.CppRuleClasses.LipoTransition;
 import com.google.devtools.build.lib.util.FileTypeSet;
@@ -139,6 +140,7 @@
               attr(CcToolchain.CC_TOOLCHAIN_DEFAULT_ATTRIBUTE_NAME, LABEL)
                   .value(CppRuleClasses.ccToolchainAttribute(env)))
           .setPreferredDependencyPredicate(Predicates.<String>or(CPP_SOURCE, C_SOURCE, CPP_HEADER))
+          .addRequiredToolchains(CppHelper.getCcToolchainType(env.getToolsRepository()))
           .build();
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
index 7cbb25f..565cb7a 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
@@ -28,6 +28,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Ordering;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
@@ -996,6 +997,11 @@
       return this;
     }
 
+    public Builder addRequiredToolchains(Label... toolchainLabels) {
+      Iterables.addAll(this.requiredToolchains, Lists.newArrayList(toolchainLabels));
+      return this;
+    }
+
     /**
      * Returns an Attribute.Builder object which contains a replica of the
      * same attribute in the parent rule if exists.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
index 1100576..87f43cc 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
@@ -87,6 +87,11 @@
   private static final ImmutableList<String> LINKOPTS_PREREQUISITE_LABEL_KINDS =
       ImmutableList.of("deps", "srcs");
 
+  /** Returns label used to select resolved cc_toolchain instances based on platform. */
+  public static Label getCcToolchainType(String toolsRepository) {
+    return Label.parseAbsoluteUnchecked(toolsRepository + "//tools/cpp:toolchain_type");
+  }
+
   private CppHelper() {
     // prevents construction
   }
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java b/src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java
index 183c8c0..83bcdad 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java
@@ -1238,8 +1238,8 @@
     useConfiguration("--experimental_dynamic_configs=on");
     AnalysisResult res = update("//foo:x");
     ConfiguredTarget topLevelTarget = Iterables.getOnlyElement(res.getTargetsToBuild());
-    assertThat(topLevelTarget.getConfiguration().getAllFragments().keySet()).containsExactly(
-        ruleClassProvider.getUniversalFragment());
+    assertThat(topLevelTarget.getConfiguration().getAllFragments().keySet())
+        .containsExactly(ruleClassProvider.getUniversalFragment(), PlatformConfiguration.class);
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/lib/packages/util/BazelMockCcSupport.java b/src/test/java/com/google/devtools/build/lib/packages/util/BazelMockCcSupport.java
index 0defa52..862b213 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/util/BazelMockCcSupport.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/util/BazelMockCcSupport.java
@@ -77,7 +77,6 @@
     config.create(
         "/bazel_tools_workspace/tools/cpp/BUILD",
         "package(default_visibility=['//visibility:public'])",
-        "toolchain_type(name = 'toolchain_type')",
         "cc_library(name = 'stl')",
         "cc_library(name = 'malloc')",
         "cc_toolchain_suite(",
@@ -123,7 +122,7 @@
         "    linker_files = ':empty',",
         "    module_map = 'crosstool.cppmap', supports_header_parsing = 1,",
         "    objcopy_files = ':empty', static_runtime_libs = [':empty'], strip_files = ':empty',",
-        ")", 
+        ")",
         "cc_toolchain(name = 'cc-compiler-armeabi-v7a', all_files = ':empty', ",
         "    compiler_files = ':empty',",
         "    cpu = 'local', dwp_files = ':empty', dynamic_runtime_libs = [':empty'], ",
@@ -145,8 +144,27 @@
         "filegroup(",
         "    name = 'link_dynamic_library',",
         "    srcs = ['link_dynamic_library.sh'],",
-        ")");
-
+        ")",
+        "toolchain_type(name = 'toolchain_type')",
+        "toolchain(",
+        "   name = 'toolchain_cc-compiler-piii',",
+        "   toolchain_type = ':toolchain_type',",
+        "   toolchain = '//third_party/crosstool/mock:cc-compiler-piii',",
+        "   target_compatible_with = [':mock_value'],",
+        ")",
+        "toolchain(",
+        "   name = 'dummy_cc_toolchain',",
+        "   toolchain_type = ':toolchain_type',",
+        "   toolchain = ':dummy_cc_toolchain_impl',",
+        ")",
+        "load(':dummy_toolchain.bzl', 'dummy_toolchain')",
+        "dummy_toolchain(name = 'dummy_cc_toolchain_impl')");
+    config.create(
+        "/bazel_tools_workspace/tools/cpp/dummy_toolchain.bzl",
+        "def _dummy_toolchain_impl(ctx):",
+        "   toolchain = platform_common.ToolchainInfo()",
+        "   return [toolchain]",
+        "dummy_toolchain = rule(_dummy_toolchain_impl, attrs = {})");
     config.create(
         "/bazel_tools_workspace/tools/cpp/CROSSTOOL",
         readCrosstoolFile());
@@ -156,6 +174,7 @@
       config.create("tools/cpp/link_dynamic_library.sh", "");
     }
     MockObjcSupport.setup(config);
+    MockPlatformSupport.setup(config, "/bazel_tools_workspace/tools/platforms");
   }
 
   @Override
diff --git a/src/test/java/com/google/devtools/build/lib/packages/util/MockPlatformSupport.java b/src/test/java/com/google/devtools/build/lib/packages/util/MockPlatformSupport.java
new file mode 100644
index 0000000..f2d89fb
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/packages/util/MockPlatformSupport.java
@@ -0,0 +1,36 @@
+// Copyright 2017 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.packages.util;
+
+import java.io.IOException;
+
+/** Mocking support for platforms and toolchains. */
+public class MockPlatformSupport {
+
+  /** Adds mocks for basic host and target platform. */
+  public static void setup(MockToolsConfig mockToolsConfig, String platformsPath)
+      throws IOException {
+    mockToolsConfig.create(
+        platformsPath + "/BUILD",
+        "package(default_visibility=['//visibility:public'])",
+        "platform(",
+        "   name = 'target_platform',",
+        "   target_platform = True,",
+        ")",
+        "platform(",
+        "   name = 'host_platform',",
+        "   host_platform = True,",
+        ")");
+  }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java
index 2547d35..2ff18b4 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java
@@ -977,6 +977,7 @@
           BazelRuleClassProvider.BAZEL_SETUP.init(builder);
           CoreRules.INSTANCE.init(builder);
           BazelRuleClassProvider.CORE_WORKSPACE_RULES.init(builder);
+          BazelRuleClassProvider.PLATFORM_RULES.init(builder);
           BazelRuleClassProvider.GENERIC_RULES.init(builder);
           BazelRuleClassProvider.CPP_RULES.init(builder);
           builder.addRuleDefinition(new OnlyCppToolchainTypeRule());
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunctionTest.java
index 86bbf07..1c0f569 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunctionTest.java
@@ -57,9 +57,10 @@
     assertThatEvaluationResult(result).hasEntryThat(toolchainsKey).isNotNull();
 
     RegisteredToolchainsValue value = result.get(toolchainsKey);
-    assertThat(value.registeredToolchains()).hasSize(2);
+    // We have two registered toolchains, and one default for c++
+    assertThat(value.registeredToolchains()).hasSize(3);
 
-    DeclaredToolchainInfo registeredToolchain1 = value.registeredToolchains().get(0);
+    DeclaredToolchainInfo registeredToolchain1 = value.registeredToolchains().get(1);
     assertThat(registeredToolchain1).isNotNull();
 
     assertThat(registeredToolchain1.toolchainType()).isEqualTo(testToolchainType);
@@ -68,7 +69,7 @@
     assertThat(registeredToolchain1.toolchainLabel())
         .isEqualTo(makeLabel("//toolchain:test_toolchain_1"));
 
-    DeclaredToolchainInfo registeredToolchain2 = value.registeredToolchains().get(1);
+    DeclaredToolchainInfo registeredToolchain2 = value.registeredToolchains().get(2);
     assertThat(registeredToolchain2).isNotNull();
 
     assertThat(registeredToolchain2.toolchainType()).isEqualTo(testToolchainType);
@@ -137,7 +138,7 @@
         requestToolchainsFromSkyframe(toolchainsKey);
     assertThatEvaluationResult(result).hasNoError();
     assertToolchainLabels(result.get(toolchainsKey))
-        .containsExactly(makeLabel("//toolchain:test_toolchain_1"));
+        .contains(makeLabel("//toolchain:test_toolchain_1"));
 
     // Re-write the WORKSPACE.
     rewriteWorkspace("register_toolchains('//toolchain:toolchain_2')");
@@ -146,7 +147,7 @@
     result = requestToolchainsFromSkyframe(toolchainsKey);
     assertThatEvaluationResult(result).hasNoError();
     assertToolchainLabels(result.get(toolchainsKey))
-        .containsExactly(makeLabel("//toolchain:test_toolchain_2"));
+        .contains(makeLabel("//toolchain:test_toolchain_2"));
   }
 
   @Test
diff --git a/src/test/shell/integration/discard_graph_edges_test.sh b/src/test/shell/integration/discard_graph_edges_test.sh
index 3325eae..aeedbeb 100755
--- a/src/test/shell/integration/discard_graph_edges_test.sh
+++ b/src/test/shell/integration/discard_graph_edges_test.sh
@@ -193,7 +193,7 @@
       || fail "env extension count $env_count too low: did you move/rename the class?"
   local ct_count="$(extract_histogram_count "$histo_file" \
        'RuleConfiguredTarget$')"
-  [[ "ct_count" -ge 28 ]] \
+  [[ "ct_count" -ge 40 ]] \
       || fail "RuleConfiguredTarget count $ct_count too low: did you move/rename the class?"
   local histo_file="$(prepare_histogram "$BUILD_FLAGS")"
   package_count="$(extract_histogram_count "$histo_file" \
diff --git a/tools/BUILD b/tools/BUILD
index 61e9abc..0432b12 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -51,7 +51,7 @@
         "//tools/jdk:package-srcs",
         "//tools/jdk:srcs",
         "//tools/launcher:srcs",
-        "//tools/platforms:package-srcs",
+        "//tools/platforms:srcs",
         "//tools/objc:srcs",
         "//tools/python:srcs",
         "//tools/test:srcs",
diff --git a/tools/cpp/BUILD b/tools/cpp/BUILD
index 1a4dc67..eb75333 100644
--- a/tools/cpp/BUILD
+++ b/tools/cpp/BUILD
@@ -204,3 +204,18 @@
     name = "link_dynamic_library",
     srcs = ["link_dynamic_library.sh"],
 )
+
+toolchain_type(name = "toolchain_type")
+
+# A dummy toolchain is necessary to satisfy toolchain resolution until platforms
+# are used in c++ by default.
+# TODO(b/64754003): Remove once platforms are used in c++ by default.
+toolchain(
+    name = "dummy_cc_toolchain",
+    toolchain = "dummy_cc_toolchain_impl",
+    toolchain_type = ":toolchain_type",
+)
+
+load(":dummy_toolchain.bzl", "dummy_toolchain")
+
+dummy_toolchain(name = "dummy_cc_toolchain_impl")
diff --git a/tools/cpp/BUILD.static b/tools/cpp/BUILD.static
index 9ae4950..aaadc5b 100644
--- a/tools/cpp/BUILD.static
+++ b/tools/cpp/BUILD.static
@@ -115,3 +115,18 @@
     name = "link_dynamic_library",
     srcs = ["link_dynamic_library.sh"],
 )
+
+toolchain_type(name = "toolchain_type")
+
+# A dummy toolchain is necessary to satisfy toolchain resolution until platforms
+# are used in c++ by default.
+# TODO(b/64754003): Remove once platforms are used in c++ by default.
+toolchain(
+    name = "dummy_cc_toolchain",
+    toolchain = "dummy_cc_toolchain_impl",
+    toolchain_type = ":toolchain_type",
+)
+
+load(":dummy_toolchain.bzl", "dummy_toolchain")
+
+dummy_toolchain(name = "dummy_cc_toolchain_impl")
diff --git a/tools/cpp/BUILD.tpl b/tools/cpp/BUILD.tpl
index 5ea5368..170fe3f 100644
--- a/tools/cpp/BUILD.tpl
+++ b/tools/cpp/BUILD.tpl
@@ -75,3 +75,18 @@
     strip_files = ":empty",
     supports_param_files = 1,
 )
+
+toolchain_type(name = "toolchain_type")
+
+# A dummy toolchain is necessary to satisfy toolchain resolution until platforms
+# are used in c++ by default.
+# TODO(b/64754003): Remove once platforms are used in c++ by default.
+toolchain(
+    name = "dummy_cc_toolchain",
+    toolchain = "dummy_cc_toolchain_impl",
+    toolchain_type = ":toolchain_type",
+)
+
+load(":dummy_toolchain.bzl", "dummy_toolchain")
+
+dummy_toolchain(name = "dummy_cc_toolchain_impl")
diff --git a/tools/cpp/cc_configure.bzl b/tools/cpp/cc_configure.bzl
index 70e2fd0..9d6d29f 100644
--- a/tools/cpp/cc_configure.bzl
+++ b/tools/cpp/cc_configure.bzl
@@ -20,6 +20,8 @@
 load("@bazel_tools//tools/cpp:lib_cc_configure.bzl", "get_cpu_value")
 
 def _impl(repository_ctx):
+  repository_ctx.symlink(
+      Label("@bazel_tools//tools/cpp:dummy_toolchain.bzl"), "dummy_toolchain.bzl")
   cpu_value = get_cpu_value(repository_ctx)
   if cpu_value == "freebsd":
     # This is defaulting to the static crosstool, we should eventually
diff --git a/tools/cpp/dummy_toolchain.bzl b/tools/cpp/dummy_toolchain.bzl
new file mode 100644
index 0000000..c787f73
--- /dev/null
+++ b/tools/cpp/dummy_toolchain.bzl
@@ -0,0 +1,23 @@
+# pylint: disable=g-bad-file-header
+# Copyright 2017 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.
+
+"""Skylark rule that stubs a toolchain."""
+def _dummy_toolchain_impl(ctx):
+  ctx = ctx  # unused argument
+  toolchain = platform_common.ToolchainInfo()
+  return [toolchain]
+
+dummy_toolchain = rule(_dummy_toolchain_impl, attrs = {})
+
diff --git a/tools/platforms/BUILD b/tools/platforms/BUILD
index 4e788ae..1b74f10 100644
--- a/tools/platforms/BUILD
+++ b/tools/platforms/BUILD
@@ -13,3 +13,95 @@
     name = "srcs",
     srcs = glob(["**"]),
 )
+
+# These match values in //src/main/java/com/google/build/lib/util:CPU.java
+constraint_setting(name = "cpu")
+
+constraint_value(
+    name = "x86_32",
+    constraint_setting = ":cpu",
+)
+
+constraint_value(
+    name = "x86_64",
+    constraint_setting = ":cpu",
+)
+
+constraint_value(
+    name = "ppc",
+    constraint_setting = ":cpu",
+)
+
+constraint_value(
+    name = "arm",
+    constraint_setting = ":cpu",
+)
+
+constraint_value(
+    name = "s390x",
+    constraint_setting = ":cpu",
+)
+
+# These match values in //src/main/java/com/google/build/lib/util:OS.java
+constraint_setting(name = "os")
+
+constraint_value(
+    name = "osx",
+    constraint_setting = ":os",
+)
+
+constraint_value(
+    name = "freebsd",
+    constraint_setting = ":os",
+)
+
+constraint_value(
+    name = "linux",
+    constraint_setting = ":os",
+)
+
+constraint_value(
+    name = "windows",
+    constraint_setting = ":os",
+)
+
+# A default platform with nothing defined.
+platform(name = "default_platform")
+
+# A default platform referring to the host system. This only exists for
+# internal build configurations, and so shouldn't be accessed by other packages.
+platform(
+    name = "host_platform",
+    cpu_constraints = [
+        ":x86_32",
+        ":x86_64",
+        ":ppc",
+        ":arm",
+        ":s390x",
+    ],
+    host_platform = True,
+    os_constraints = [
+        ":osx",
+        ":freebsd",
+        ":linux",
+        ":windows",
+    ],
+)
+
+platform(
+    name = "target_platform",
+    cpu_constraints = [
+        ":x86_32",
+        ":x86_64",
+        ":ppc",
+        ":arm",
+        ":s390x",
+    ],
+    os_constraints = [
+        ":osx",
+        ":freebsd",
+        ":linux",
+        ":windows",
+    ],
+    target_platform = True,
+)