Skylark: configuration fragments for host configuration can now be accessed via ctx.host_fragments.

--
MOS_MIGRATED_REVID=102490502
diff --git a/site/docs/skylark/rules.md b/site/docs/skylark/rules.md
index f450fd0..287fb2f 100644
--- a/site/docs/skylark/rules.md
+++ b/site/docs/skylark/rules.md
@@ -235,11 +235,16 @@
 
 my_rule = rule(
     implementation=impl,
-    fragments = ["java"],
+    fragments = ["java"],      #Required fragments of the target configuration
+    host_fragments = ["java"], #Required fragments of the host configuration
     ...
 )
 ```
 
+`ctx.fragments` only provides configuration fragments for the target
+configuration. If you want to access fragments for the host configuration,
+please use `ctx.host_fragments` instead.
+
 Providers
 ---------
 
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
index af05afd..b6affca 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
@@ -39,6 +39,7 @@
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
 import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
+import com.google.devtools.build.lib.analysis.config.FragmentCollection;
 import com.google.devtools.build.lib.collect.ImmutableSortedKeyListMultimap;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
@@ -257,26 +258,44 @@
    * Returns a configuration fragment for this this target.
    */
   @Nullable
-  public <T extends Fragment> T getFragment(Class<T> fragment) {
+  public <T extends Fragment> T getFragment(Class<T> fragment, ConfigurationTransition config) {
     // TODO(bazel-team): The fragments can also be accessed directly through BuildConfiguration.
     // Can we lock that down somehow?
-    Preconditions.checkArgument(isLegalFragment(fragment),
-        "%s does not have access to %s", rule.getRuleClass(), fragment);
-    return getConfiguration().getFragment(fragment);
+    Preconditions.checkArgument(isLegalFragment(fragment, config),
+        "%s does not have access to '%s' in %s configuration", rule.getRuleClass(),
+        fragment.getSimpleName(), FragmentCollection.getConfigurationName(config));
+    return getConfiguration(config).getFragment(fragment);
   }
 
   @Nullable
-  public Fragment getSkylarkFragment(String name) {
-    Class<? extends Fragment> fragmentClass = getConfiguration().getSkylarkFragmentByName(name);
-    return (fragmentClass == null) ? null : getFragment(fragmentClass);
+  public <T extends Fragment> T getFragment(Class<T> fragment) {
+    // NONE means target configuration.
+    return getFragment(fragment, ConfigurationTransition.NONE);
   }
 
-  public ImmutableCollection<String> getSkylarkFragmentNames() {
-    return getConfiguration().getSkylarkFragmentNames();
+  @Nullable
+  public Fragment getSkylarkFragment(String name, ConfigurationTransition config) {
+    Class<? extends Fragment> fragmentClass =
+        getConfiguration(config).getSkylarkFragmentByName(name);
+    return (fragmentClass == null) ? null : getFragment(fragmentClass, config);
+  }
+
+  public ImmutableCollection<String> getSkylarkFragmentNames(ConfigurationTransition config) {
+    return getConfiguration(config).getSkylarkFragmentNames();
+  }
+
+  public <T extends Fragment> boolean isLegalFragment(
+      Class<T> fragment, ConfigurationTransition config) {
+    return rule.getRuleClassObject().isLegalConfigurationFragment(fragment, config);
   }
 
   public <T extends Fragment> boolean isLegalFragment(Class<T> fragment) {
-    return rule.getRuleClassObject().isLegalConfigurationFragment(fragment);
+    // NONE means target configuration.
+    return isLegalFragment(fragment, ConfigurationTransition.NONE);
+  }
+  
+  protected BuildConfiguration getConfiguration(ConfigurationTransition config) {
+    return config.equals(ConfigurationTransition.HOST) ? hostConfiguration : getConfiguration();
   }
 
   @Override
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/FragmentCollection.java b/src/main/java/com/google/devtools/build/lib/analysis/config/FragmentCollection.java
index d649f47..a7d935a 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/FragmentCollection.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/FragmentCollection.java
@@ -17,6 +17,7 @@
 import com.google.common.collect.ImmutableCollection;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
 import com.google.devtools.build.lib.syntax.ClassObject;
 import com.google.devtools.build.lib.syntax.SkylarkModule;
 
@@ -30,30 +31,38 @@
 @SkylarkModule(name = "fragments", documented = false, doc = "")
 public class FragmentCollection implements ClassObject {
   private final RuleContext ruleContext;
+  private final ConfigurationTransition config;
 
-  public FragmentCollection(RuleContext ruleContext) {
+  public FragmentCollection(RuleContext ruleContext, ConfigurationTransition config) {
     this.ruleContext = ruleContext;
+    this.config = config;
   }
 
   @Override
   @Nullable
   public Object getValue(String name) {
-    return ruleContext.getSkylarkFragment(name);
+    return ruleContext.getSkylarkFragment(name, config);
   }
 
   @Override
   public ImmutableCollection<String> getKeys() {
-    return ruleContext.getSkylarkFragmentNames();
+    return ruleContext.getSkylarkFragmentNames(config);
   }
 
   @Override
   @Nullable
   public String errorMessage(String name) {
-    return String.format("There is no configuration fragment named '%s'. Available fragments: %s",
-        name, printKeys());
+    return String.format(
+        "There is no configuration fragment named '%s' in %s configuration. "
+        + "Available fragments: %s",
+        name, getConfigurationName(config), printKeys());
   }
 
   private String printKeys() {
     return String.format("'%s'", Joiner.on("', '").join(getKeys()));
   }
+
+  public static String getConfigurationName(ConfigurationTransition config) {
+    return (config == ConfigurationTransition.HOST) ? "host" : "target";
+  }
 }
\ No newline at end of file
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 59fcbb5..1202f04 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
@@ -31,6 +31,7 @@
 import com.google.common.collect.Ordering;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
 import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
 import com.google.devtools.build.lib.syntax.Argument;
 import com.google.devtools.build.lib.syntax.BaseFunction;
@@ -501,7 +502,8 @@
     private SkylarkEnvironment ruleDefinitionEnvironment = null;
     private Set<Class<?>> configurationFragments = new LinkedHashSet<>();
     private MissingFragmentPolicy missingFragmentPolicy = MissingFragmentPolicy.FAIL_ANALYSIS;
-    private Set<String> requiredFragmentNames = new LinkedHashSet<>();
+    private Map<ConfigurationTransition, ImmutableSet<String>> requiredFragmentNames =
+        new LinkedHashMap<>();
     private FragmentClassNameResolver fragmentNameResolver;
 
     private boolean supportsConstraintChecking = true;
@@ -590,7 +592,7 @@
           configuredTargetFactory, validityPredicate, preferredDependencyPredicate,
           ImmutableSet.copyOf(advertisedProviders), configuredTargetFunction,
           externalBindingsFunction, ruleDefinitionEnvironment, configurationFragments,
-          requiredFragmentNames, fragmentNameResolver, missingFragmentPolicy,
+          ImmutableMap.copyOf(requiredFragmentNames), fragmentNameResolver, missingFragmentPolicy,
           supportsConstraintChecking, attributes.values().toArray(new Attribute[0]));
     }
 
@@ -615,14 +617,18 @@
       this.missingFragmentPolicy = missingFragmentPolicy;
       return this;
     }
-    
+
     /**
-     * Does the same as {@link #requiresConfigurationFragments(Class...)}, except for taking names
-     * of fragments instead of classes.
+     * Declares the configuration fragments that are required by this rule.
+     *
+     * <p>In contrast to {@link #requiresConfigurationFragments(Class...)}, this method a) takes the
+     * names of fragments instead of their classes and b) distinguishes whether the fragments can be
+     * accessed in host (HOST) or target (NONE) configuration.
      */
     public Builder requiresConfigurationFragments(
-        FragmentClassNameResolver fragmentNameResolver, String... configurationFragmentNames) {
-      Collections.addAll(requiredFragmentNames, configurationFragmentNames);
+        FragmentClassNameResolver fragmentNameResolver,
+        Map<ConfigurationTransition, ImmutableSet<String>> configurationFragmentNames) {
+      requiredFragmentNames.putAll(configurationFragmentNames);
       this.fragmentNameResolver = fragmentNameResolver;
       return this;
     }
@@ -974,10 +980,12 @@
   private final ImmutableSet<Class<?>> requiredConfigurationFragments;
 
   /**
-   * Same idea as requiredConfigurationFragments, but stores fragments by name instead of by class
+   * A dictionary that maps configurations (NONE for target configuration, HOST for host
+   * configuration) to lists of names of required configuration fragments.
    */
-  private final ImmutableSet<String> requiredConfigurationFragmentNames;
-  
+  private final ImmutableMap<ConfigurationTransition, ImmutableSet<String>>
+      requiredConfigurationFragmentNames;
+
   /**
    * Used to resolve the names of fragments in order to compare them to values in {@link
    * #requiredConfigurationFragmentNames}
@@ -1037,7 +1045,8 @@
         externalBindingsFunction,
         ruleDefinitionEnvironment,
         allowedConfigurationFragments,
-        ImmutableSet.<String>of(), null,
+        ImmutableMap.<ConfigurationTransition, ImmutableSet<String>>of(),
+        null, // FragmentClassNameResolver
         missingFragmentPolicy,
         supportsConstraintChecking,
         attributes);
@@ -1078,7 +1087,7 @@
       Function<? super Rule, Map<String, Label>> externalBindingsFunction,
       @Nullable SkylarkEnvironment ruleDefinitionEnvironment,
       Set<Class<?>> allowedConfigurationFragments,
-      Set<String> allowedConfigurationFragmentNames,
+      ImmutableMap<ConfigurationTransition, ImmutableSet<String>> allowedConfigurationFragmentNames,
       @Nullable FragmentClassNameResolver fragmentNameResolver,
       MissingFragmentPolicy missingFragmentPolicy,
       boolean supportsConstraintChecking,
@@ -1102,8 +1111,7 @@
     this.workspaceOnly = workspaceOnly;
     this.outputsDefaultExecutable = outputsDefaultExecutable;
     this.requiredConfigurationFragments = ImmutableSet.copyOf(allowedConfigurationFragments);
-    this.requiredConfigurationFragmentNames =
-        ImmutableSet.copyOf(allowedConfigurationFragmentNames);
+    this.requiredConfigurationFragmentNames = allowedConfigurationFragmentNames;
     this.fragmentNameResolver = fragmentNameResolver;
     this.missingFragmentPolicy = missingFragmentPolicy;
     this.supportsConstraintChecking = supportsConstraintChecking;
@@ -1260,24 +1268,32 @@
   }
 
   /**
-   * Checks if the configuration fragment may be accessed (i.e., if it's declared). If no fragments
-   * are declared, this allows access to all fragments for backwards compatibility.
+   * Checks if the configuration fragment may be accessed (i.e., if it's declared) in the specified
+   * configuration (target or host).
    */
-  public boolean isLegalConfigurationFragment(Class<?> configurationFragment) {
+  public boolean isLegalConfigurationFragment(
+      Class<?> configurationFragment, ConfigurationTransition config) {
     return requiredConfigurationFragments.contains(configurationFragment)
-        || hasLegalFragmentName(configurationFragment);
+        || hasLegalFragmentName(configurationFragment, config);
+  }
+
+  public boolean isLegalConfigurationFragment(Class<?> configurationFragment) {
+    // NONE means target configuration.
+    return isLegalConfigurationFragment(configurationFragment, ConfigurationTransition.NONE);
   }
 
   /**
-   * Checks whether the name of the given fragment class was declared as required fragment
+   * Checks whether the name of the given fragment class was declared as required fragment in the
+   * specified configuration (target or host).
    */
-  private boolean hasLegalFragmentName(Class<?> configurationFragment) {
+  private boolean hasLegalFragmentName(
+      Class<?> configurationFragment, ConfigurationTransition config) {
     if (fragmentNameResolver == null) {
       return false;
     }
 
     String name = fragmentNameResolver.resolveName(configurationFragment);
-    return (name != null && requiredConfigurationFragmentNames.contains(name));
+    return (name != null && requiredConfigurationFragmentNames.get(config).contains(name));
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
index e254034..42449c5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
@@ -16,6 +16,7 @@
 
 import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.DATA;
 import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST;
+import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.NONE;
 import static com.google.devtools.build.lib.packages.Attribute.attr;
 import static com.google.devtools.build.lib.packages.Type.BOOLEAN;
 import static com.google.devtools.build.lib.packages.Type.INTEGER;
@@ -33,7 +34,7 @@
 import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
+import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.RunUnder;
@@ -78,6 +79,7 @@
 import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor;
 import com.google.devtools.build.lib.vfs.PathFragment;
 
+import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ExecutionException;
 
@@ -232,72 +234,91 @@
         @Param(name = "output_to_genfiles", type = Boolean.class, defaultValue = "False",
             doc = "If true, the files will be generated in the genfiles directory instead of the "
             + "bin directory. This is used for compatibility with existing rules."),
-        @Param(name = "fragments", type = SkylarkList.class, generic1 = String.class,
+       @Param(name = "fragments", type = SkylarkList.class, generic1 = String.class,
            defaultValue = "[]",
-           doc = "List of names of configuration fragments that the rule requires.")},
+           doc =
+           "List of names of configuration fragments that the rule requires "
+           + "in target configuration."),
+       @Param(name = "host_fragments", type = SkylarkList.class, generic1 = String.class,
+           defaultValue = "[]",
+           doc =
+           "List of names of configuration fragments that the rule requires "
+           + "in host configuration.")},
       useAst = true, useEnvironment = true)
   private static final BuiltinFunction rule = new BuiltinFunction("rule") {
-      @SuppressWarnings({"rawtypes", "unchecked"}) // castMap produces
-      // an Attribute.Builder instead of a Attribute.Builder<?> but it's OK.
-      public BaseFunction invoke(BaseFunction implementation, Boolean test, Object attrs,
-          Object implicitOutputs, Boolean executable, Boolean outputToGenfiles,
-          SkylarkList fragments, FuncallExpression ast, Environment funcallEnv)
-          throws EvalException, ConversionException {
+    @SuppressWarnings({"rawtypes", "unchecked"}) // castMap produces
+    // an Attribute.Builder instead of a Attribute.Builder<?> but it's OK.
+    public BaseFunction invoke(BaseFunction implementation, Boolean test, Object attrs,
+        Object implicitOutputs, Boolean executable, Boolean outputToGenfiles, SkylarkList fragments,
+        SkylarkList hostFragments, FuncallExpression ast, Environment funcallEnv)
+        throws EvalException, ConversionException {
+      funcallEnv.checkLoadingPhase("rule", ast.getLocation());
+      RuleClassType type = test ? RuleClassType.TEST : RuleClassType.NORMAL;
+      RuleClass parent = test ? testBaseRule : (executable ? binaryBaseRule : baseRule);
 
-        funcallEnv.checkLoadingPhase("rule", ast.getLocation());
-        RuleClassType type = test ? RuleClassType.TEST : RuleClassType.NORMAL;
-        RuleClass parent = test ? testBaseRule : (executable ? binaryBaseRule : baseRule);
+      // We'll set the name later, pass the empty string for now.
+      RuleClass.Builder builder = new RuleClass.Builder("", type, true, parent);
 
-        // We'll set the name later, pass the empty string for now.
-        RuleClass.Builder builder = new RuleClass.Builder("", type, true, parent);
-
-        if (attrs != Runtime.NONE) {
-          for (Map.Entry<String, Attribute.Builder> attr : castMap(
-              attrs, String.class, Attribute.Builder.class, "attrs").entrySet()) {
-            Attribute.Builder<?> attrBuilder = (Attribute.Builder<?>) attr.getValue();
-            String attrName = attributeToNative(attr.getKey(), ast.getLocation(),
-                attrBuilder.hasLateBoundValue());
-            builder.addOrOverrideAttribute(attrBuilder.build(attrName));
-          }
+      if (attrs != Runtime.NONE) {
+        for (Map.Entry<String, Attribute.Builder> attr :
+            castMap(attrs, String.class, Attribute.Builder.class, "attrs").entrySet()) {
+          Attribute.Builder<?> attrBuilder = (Attribute.Builder<?>) attr.getValue();
+          String attrName =
+              attributeToNative(attr.getKey(), ast.getLocation(), attrBuilder.hasLateBoundValue());
+          builder.addOrOverrideAttribute(attrBuilder.build(attrName));
         }
-        if (executable || test) {
-          builder.addOrOverrideAttribute(
-              attr("$is_executable", BOOLEAN).value(true)
-              .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target")
-              .build());
-          builder.setOutputsDefaultExecutable();
-        }
+      }
+      if (executable || test) {
+        builder.addOrOverrideAttribute(
+            attr("$is_executable", BOOLEAN)
+                .value(true)
+                .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target")
+                .build());
+        builder.setOutputsDefaultExecutable();
+      }
 
-        if (implicitOutputs != Runtime.NONE) {
-          if (implicitOutputs instanceof BaseFunction) {
-            BaseFunction func = (BaseFunction) implicitOutputs;
-            final SkylarkCallbackFunction callback =
-                new SkylarkCallbackFunction(func, ast, (SkylarkEnvironment) funcallEnv);
-            builder.setImplicitOutputsFunction(
-                new SkylarkImplicitOutputsFunctionWithCallback(callback, ast.getLocation()));
-          } else {
-            builder.setImplicitOutputsFunction(new SkylarkImplicitOutputsFunctionWithMap(
-                ImmutableMap.copyOf(castMap(implicitOutputs, String.class, String.class,
-                        "implicit outputs of the rule class"))));
-            }
+      if (implicitOutputs != Runtime.NONE) {
+        if (implicitOutputs instanceof BaseFunction) {
+          BaseFunction func = (BaseFunction) implicitOutputs;
+          final SkylarkCallbackFunction callback =
+              new SkylarkCallbackFunction(func, ast, (SkylarkEnvironment) funcallEnv);
+          builder.setImplicitOutputsFunction(
+              new SkylarkImplicitOutputsFunctionWithCallback(callback, ast.getLocation()));
+        } else {
+          builder.setImplicitOutputsFunction(
+              new SkylarkImplicitOutputsFunctionWithMap(ImmutableMap.copyOf(castMap(implicitOutputs,
+                  String.class, String.class, "implicit outputs of the rule class"))));
         }
+      }
 
-        if (outputToGenfiles) {
-          builder.setOutputToGenfiles();
-        }
+      if (outputToGenfiles) {
+        builder.setOutputToGenfiles();
+      }
 
-        if (!fragments.isEmpty()) {
-          builder.requiresConfigurationFragments(
-              new SkylarkModuleNameResolver(),
-              Iterables.toArray(castList(fragments, String.class), String.class));
-        }
+      registerRequiredFragments(fragments, hostFragments, builder);
 
-        builder.setConfiguredTargetFunction(implementation);
-        builder.setRuleDefinitionEnvironment(
-            ((SkylarkEnvironment) funcallEnv).getGlobalEnvironment());
-        return new RuleFunction(builder, type);
-        }
-      };
+      builder.setConfiguredTargetFunction(implementation);
+      builder.setRuleDefinitionEnvironment(
+          ((SkylarkEnvironment) funcallEnv).getGlobalEnvironment());
+      return new RuleFunction(builder, type);
+    }
+
+    private void registerRequiredFragments(
+        SkylarkList fragments, SkylarkList hostFragments, RuleClass.Builder builder) {
+      Map<ConfigurationTransition, ImmutableSet<String>> map = new HashMap<>();
+      addFragmentsToMap(map, fragments, NONE); // NONE represents target configuration
+      addFragmentsToMap(map, hostFragments, HOST);
+
+      builder.requiresConfigurationFragments(new SkylarkModuleNameResolver(), map);
+    }
+
+    private void addFragmentsToMap(Map<ConfigurationTransition, ImmutableSet<String>> map,
+        SkylarkList fragments, ConfigurationTransition config) {
+      if (!fragments.isEmpty()) {
+        map.put(config, ImmutableSet.copyOf(castList(fragments, String.class)));
+      }
+    }
+  };
 
   // This class is needed for testing
   static final class RuleFunction extends BaseFunction {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
index af962f0..d3909fb 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
@@ -36,6 +36,7 @@
 import com.google.devtools.build.lib.analysis.config.FragmentCollection;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
 import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
 import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SkylarkImplicitOutputsFunction;
 import com.google.devtools.build.lib.packages.OutputFile;
@@ -94,9 +95,11 @@
     });
 
   private final RuleContext ruleContext;
-  
+
   private final FragmentCollection fragments;
 
+  private final FragmentCollection hostFragments;
+
   // TODO(bazel-team): support configurable attributes.
   private final SkylarkClassObject attrObject;
 
@@ -120,7 +123,8 @@
    */
   public SkylarkRuleContext(RuleContext ruleContext) throws EvalException {
     this.ruleContext = Preconditions.checkNotNull(ruleContext);
-    fragments = new FragmentCollection(ruleContext);
+    fragments = new FragmentCollection(ruleContext, ConfigurationTransition.NONE);
+    hostFragments = new FragmentCollection(ruleContext, ConfigurationTransition.HOST);
 
     HashMap<String, Object> outputsBuilder = new HashMap<>();
     if (ruleContext.getRule().getRuleClassObject().outputsDefaultExecutable()) {
@@ -326,19 +330,28 @@
     return ruleContext.getLabel();
   }
 
-  @SkylarkCallable(
-    name = "fragments",
-    structField = true,
-    doc =
-        "Allows access to configuration fragments. Possible fields are <code>cpp</code>, "
-            + "<code>java</code> and <code>jvm</code>. "
-            + "However, rules have to declare their required fragments in order to access them "
-            + "(see <a href=\"../rules.html#fragments\">here</a>)."
-  )
+  @SkylarkCallable(name = "fragments", structField = true,
+      doc =
+      "Allows access to configuration fragments in target configuration. "
+      + "Possible fields are <code>cpp</code>, "
+      + "<code>java</code> and <code>jvm</code>. "
+      + "However, rules have to declare their required fragments in order to access them "
+      + "(see <a href=\"../rules.html#fragments\">here</a>).")
   public FragmentCollection getFragments() {
     return fragments;
   }
 
+  @SkylarkCallable(name = "host_fragments", structField = true,
+      doc =
+      "Allows access to configuration fragments in host configuration. "
+      + "Possible fields are <code>cpp</code>, "
+      + "<code>java</code> and <code>jvm</code>. "
+      + "However, rules have to declare their required fragments in order to access them "
+      + "(see <a href=\"../rules.html#fragments\">here</a>).")
+  public FragmentCollection getHostFragments() {
+    return hostFragments;
+  }
+
   @SkylarkCallable(name = "configuration", structField = true,
       doc = "Returns the default configuration. See the <a href=\"configuration.html\">"
           + "configuration</a> type for more details.")