[6.4.0] Add `--consistent_labels` flag to all query commands (#19567)

If enabled, labels are emitted as if by the Starlark `str` function
applied to a `Label` instance. This is useful for tools that need to
match the output of different query commands and/or labels emitted by
rules. If not enabled, output formatters are free to emit apparent
repository names (relative to the main repository) instead to make the
output more readable.

This is implemented by replacing all `Label#toString()` calls in query
code with an indirection through a `LabelPrinter` object constructed in
a central place. There are currently three types of instances:
* `canonical` behaves just like `str(Label(...))`;
* `apparent` matches the current behavior, which renders main repo
labels in repo-relative form and attempts to use the apparent names for
external repos if possible;
* `legacy` is used in all non-query callsites and uses
`Label#toString()`.

Fixes #17864

RELNOTES: The new `--consistent_labels` option on `query`, `cquery`, and
`aquery` can be used to force consistent label formatting across all
output modes that is also compatible with `str(Label(...))` in Starlark.

Closes #19508.

PiperOrigin-RevId: 566723654
Change-Id: Ifa08a82e281f423faa971c46bf7277cb307698b5

---------

Co-authored-by: Fabian Meumertzheim <fabian@meumertzhe.im>
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/modcommand/BUILD b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/modcommand/BUILD
index 53d3a3d..0af7624 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/modcommand/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/modcommand/BUILD
@@ -21,6 +21,7 @@
         "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:repo_rule_value",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/packages",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/query2/query/output",
         "//src/main/java/com/google/devtools/build/lib/util:maybe_complete_set",
         "//src/main/java/com/google/devtools/common/options",
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/modcommand/ModExecutor.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/modcommand/ModExecutor.java
index 9a84d05..861d5d7 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/modcommand/ModExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/modcommand/ModExecutor.java
@@ -38,6 +38,7 @@
 import com.google.devtools.build.lib.bazel.bzlmod.modcommand.ModExecutor.ResultNode.IsExpanded;
 import com.google.devtools.build.lib.bazel.bzlmod.modcommand.ModExecutor.ResultNode.IsIndirect;
 import com.google.devtools.build.lib.bazel.bzlmod.modcommand.ModExecutor.ResultNode.NodeMetadata;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.RawAttributeMapper;
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.query2.query.output.BuildOutputFormatter.AttributeReader;
@@ -627,7 +628,8 @@
           new TargetOutputter(
               this.printer,
               (rule, attr) -> RawAttributeMapper.of(rule).isConfigurable(attr.getName()),
-              "\n");
+              "\n",
+              LabelPrinter.legacy());
     }
 
     private void outputRule(Rule rule) {
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/commands/BUILD b/src/main/java/com/google/devtools/build/lib/bazel/commands/BUILD
index 07f59db..bb559c6 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/commands/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/bazel/commands/BUILD
@@ -39,6 +39,7 @@
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/events",
         "//src/main/java/com/google/devtools/build/lib/packages",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/pkgcache",
         "//src/main/java/com/google/devtools/build/lib/query2/common:abstract-blaze-query-env",
         "//src/main/java/com/google/devtools/build/lib/query2/common:universe-scope",
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/commands/FetchCommand.java b/src/main/java/com/google/devtools/build/lib/bazel/commands/FetchCommand.java
index 1d3ba54..73dcdeb 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/commands/FetchCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/commands/FetchCommand.java
@@ -22,6 +22,7 @@
 import com.google.devtools.build.lib.cmdline.TargetPattern;
 import com.google.devtools.build.lib.cmdline.TargetPattern.Parser;
 import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.pkgcache.PackageOptions;
 import com.google.devtools.build.lib.query2.common.AbstractBlazeQueryEnvironment;
@@ -127,7 +128,8 @@
             threadsOption.threads,
             EnumSet.noneOf(Setting.class),
             /* useGraphlessQuery= */ true,
-            mainRepoTargetParser);
+            mainRepoTargetParser,
+            LabelPrinter.legacy());
 
     // 1. Parse query:
     QueryExpression expr;
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/AqueryProcessor.java b/src/main/java/com/google/devtools/build/lib/buildtool/AqueryProcessor.java
index 998fd8f..7139904 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/AqueryProcessor.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/AqueryProcessor.java
@@ -19,6 +19,7 @@
 import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.cmdline.TargetPattern;
 import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions;
 import com.google.devtools.build.lib.query2.PostAnalysisQueryEnvironment;
 import com.google.devtools.build.lib.query2.PostAnalysisQueryEnvironment.TopLevelConfigurations;
 import com.google.devtools.build.lib.query2.aquery.ActionGraphProtoOutputFormatterCallback;
@@ -53,6 +54,7 @@
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
 import javax.annotation.Nullable;
+import net.starlark.java.eval.StarlarkSemantics;
 
 /** Performs {@code aquery} processing. */
 public final class AqueryProcessor extends PostAnalysisQueryProcessor<KeyedConfiguredTargetValue> {
@@ -133,6 +135,9 @@
             .build();
     AqueryOptions aqueryOptions = request.getOptions(AqueryOptions.class);
 
+    StarlarkSemantics starlarkSemantics =
+        env.getSkyframeExecutor()
+            .getEffectiveStarlarkSemantics(env.getOptions().getOptions(BuildLanguageOptions.class));
     ActionGraphQueryEnvironment queryEnvironment =
         new ActionGraphQueryEnvironment(
             request.getKeepGoing(),
@@ -143,7 +148,10 @@
             mainRepoTargetParser,
             env.getPackageManager().getPackagePath(),
             () -> walkableGraph,
-            aqueryOptions);
+            aqueryOptions,
+            request
+                .getOptions(AqueryOptions.class)
+                .getLabelPrinter(starlarkSemantics, mainRepoTargetParser.getRepoMapping()));
     queryEnvironment.setActionFilters(actionFilters);
 
     return queryEnvironment;
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/CqueryProcessor.java b/src/main/java/com/google/devtools/build/lib/buildtool/CqueryProcessor.java
index cc1f8a9..102c4f5 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/CqueryProcessor.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/CqueryProcessor.java
@@ -16,6 +16,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.cmdline.TargetPattern;
+import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions;
 import com.google.devtools.build.lib.query2.PostAnalysisQueryEnvironment.TopLevelConfigurations;
 import com.google.devtools.build.lib.query2.cquery.ConfiguredTargetQueryEnvironment;
 import com.google.devtools.build.lib.query2.cquery.CqueryOptions;
@@ -26,6 +27,7 @@
 import com.google.devtools.build.skyframe.SkyKey;
 import com.google.devtools.build.skyframe.WalkableGraph;
 import java.util.Collection;
+import net.starlark.java.eval.StarlarkSemantics;
 
 /** Performs {@code cquery} processing. */
 public final class CqueryProcessor extends PostAnalysisQueryProcessor<KeyedConfiguredTarget> {
@@ -50,6 +52,9 @@
             .addAll(env.getRuntime().getQueryFunctions())
             .build();
     CqueryOptions cqueryOptions = request.getOptions(CqueryOptions.class);
+    StarlarkSemantics starlarkSemantics =
+        env.getSkyframeExecutor()
+            .getEffectiveStarlarkSemantics(env.getOptions().getOptions(BuildLanguageOptions.class));
     return new ConfiguredTargetQueryEnvironment(
         request.getKeepGoing(),
         env.getReporter(),
@@ -61,6 +66,9 @@
         env.getPackageManager().getPackagePath(),
         () -> walkableGraph,
         cqueryOptions,
-        request.getTopLevelArtifactContext());
+        request.getTopLevelArtifactContext(),
+        request
+            .getOptions(CqueryOptions.class)
+            .getLabelPrinter(starlarkSemantics, mainRepoTargetParser.getRepoMapping()));
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/PostAnalysisQueryProcessor.java b/src/main/java/com/google/devtools/build/lib/buildtool/PostAnalysisQueryProcessor.java
index de06336..d083276 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/PostAnalysisQueryProcessor.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/PostAnalysisQueryProcessor.java
@@ -19,6 +19,7 @@
 import com.google.devtools.build.lib.buildtool.BuildTool.ExitException;
 import com.google.devtools.build.lib.cmdline.TargetPattern;
 import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions;
 import com.google.devtools.build.lib.query2.NamedThreadSafeOutputFormatterCallback;
 import com.google.devtools.build.lib.query2.PostAnalysisQueryEnvironment;
 import com.google.devtools.build.lib.query2.PostAnalysisQueryEnvironment.TopLevelConfigurations;
@@ -166,7 +167,10 @@
             env.getSkyframeExecutor(),
             hostConfiguration,
             runtime.getRuleClassProvider().getTrimmingTransitionFactory(),
-            env.getPackageManager());
+            env.getPackageManager(),
+            env.getSkyframeExecutor()
+                .getEffectiveStarlarkSemantics(
+                    env.getOptions().getOptions(BuildLanguageOptions.class)));
     String outputFormat = postAnalysisQueryEnvironment.getOutputFormat();
     NamedThreadSafeOutputFormatterCallback<T> callback =
         NamedThreadSafeOutputFormatterCallback.selectCallback(outputFormat, callbacks);
diff --git a/src/main/java/com/google/devtools/build/lib/packages/AttributeFormatter.java b/src/main/java/com/google/devtools/build/lib/packages/AttributeFormatter.java
index 1cdf51a..eafcdbb 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/AttributeFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/AttributeFormatter.java
@@ -92,7 +92,23 @@
         attr.getType(),
         value,
         explicitlySpecified,
-        encodeBooleanAndTriStateAsIntegerAndString);
+        encodeBooleanAndTriStateAsIntegerAndString,
+        LabelPrinter.legacy());
+  }
+
+  public static Build.Attribute getAttributeProto(
+      Attribute attr,
+      @Nullable Object value,
+      boolean explicitlySpecified,
+      boolean encodeBooleanAndTriStateAsIntegerAndString,
+      LabelPrinter labelPrinter) {
+    return getAttributeProto(
+        attr.getName(),
+        attr.getType(),
+        value,
+        explicitlySpecified,
+        encodeBooleanAndTriStateAsIntegerAndString,
+        labelPrinter);
   }
 
   private static Build.Attribute getAttributeProto(
@@ -100,7 +116,8 @@
       Type<?> type,
       @Nullable Object value,
       boolean explicitlySpecified,
-      boolean encodeBooleanAndTriStateAsIntegerAndString) {
+      boolean encodeBooleanAndTriStateAsIntegerAndString,
+      LabelPrinter labelPrinter) {
     Build.Attribute.Builder attrPb = Build.Attribute.newBuilder();
     attrPb.setName(name);
     attrPb.setExplicitlySpecified(explicitlySpecified);
@@ -108,13 +125,13 @@
 
     if (value instanceof SelectorList<?>) {
       attrPb.setType(Discriminator.SELECTOR_LIST);
-      writeSelectorListToBuilder(attrPb, type, (SelectorList<?>) value);
+      writeSelectorListToBuilder(attrPb, type, (SelectorList<?>) value, labelPrinter);
     } else {
       attrPb.setType(ProtoUtils.getDiscriminatorFromType(type));
       if (value != null) {
         AttributeBuilderAdapter adapter =
             new AttributeBuilderAdapter(attrPb, encodeBooleanAndTriStateAsIntegerAndString);
-        writeAttributeValueToBuilder(adapter, type, value);
+        writeAttributeValueToBuilder(adapter, type, value, labelPrinter);
       }
     }
 
@@ -130,7 +147,10 @@
   }
 
   private static void writeSelectorListToBuilder(
-      Build.Attribute.Builder attrPb, Type<?> type, SelectorList<?> selectorList) {
+      Build.Attribute.Builder attrPb,
+      Type<?> type,
+      SelectorList<?> selectorList,
+      LabelPrinter labelPrinter) {
     Build.Attribute.SelectorList.Builder selectorListBuilder =
         Build.Attribute.SelectorList.newBuilder();
     selectorListBuilder.setType(ProtoUtils.getDiscriminatorFromType(type));
@@ -147,13 +167,16 @@
         Label condition = entry.getKey();
         SelectorEntry.Builder selectorEntryBuilder =
             SelectorEntry.newBuilder()
-                .setLabel(condition.toString())
+                .setLabel(labelPrinter.toString(condition))
                 .setIsDefaultValue(!selector.isValueSet(condition));
 
         Object conditionValue = entry.getValue();
         if (conditionValue != null) {
           writeAttributeValueToBuilder(
-              new SelectorEntryBuilderAdapter(selectorEntryBuilder), type, conditionValue);
+              new SelectorEntryBuilderAdapter(selectorEntryBuilder),
+                  type,
+                  conditionValue,
+                  labelPrinter);
         }
         selectorBuilder.addEntries(selectorEntryBuilder);
       }
@@ -166,26 +189,30 @@
    * Set the appropriate type and value. Since string and string list store values for multiple
    * types, use the toString() method on the objects instead of casting them.
    */
+  @SuppressWarnings("unchecked")
   private static void writeAttributeValueToBuilder(
-      AttributeValueBuilderAdapter builder, Type<?> type, Object value) {
+      AttributeValueBuilderAdapter builder, Type<?> type, Object value, LabelPrinter labelPrinter) {
     if (type == INTEGER) {
       builder.setIntValue(((StarlarkInt) value).toIntUnchecked());
-    } else if (type == STRING
-        || type == LABEL
+    } else if (type == STRING) {
+      builder.setStringValue(value.toString());
+    } else if (type == LABEL
         || type == NODEP_LABEL
         || type == OUTPUT
         || type == GENQUERY_SCOPE_TYPE) {
 
-      builder.setStringValue(value.toString());
-    } else if (type == STRING_LIST
-        || type == LABEL_LIST
-        || type == NODEP_LABEL_LIST
-        || type == OUTPUT_LIST
-        || type == DISTRIBUTIONS
-        || type == GENQUERY_SCOPE_TYPE_LIST) {
+      builder.setStringValue(labelPrinter.toString((Label) value));
+    } else if (type == STRING_LIST || type == DISTRIBUTIONS) {
       for (Object entry : (Collection<?>) value) {
         builder.addStringListValue(entry.toString());
       }
+    } else if (type == LABEL_LIST
+        || type == NODEP_LABEL_LIST
+        || type == OUTPUT_LIST
+        || type == GENQUERY_SCOPE_TYPE_LIST) {
+      for (Label entry : (Collection<Label>) value) {
+        builder.addStringListValue(labelPrinter.toString(entry));
+      }
     } else if (type == INTEGER_LIST) {
       for (Object elem : (Collection<?>) value) {
         builder.addIntListValue(((StarlarkInt) elem).toIntUnchecked());
@@ -205,7 +232,6 @@
       }
       builder.setLicense(licensePb);
     } else if (type == STRING_DICT) {
-      @SuppressWarnings("unchecked")
       Map<String, String> dict = (Map<String, String>) value;
       for (Map.Entry<String, String> keyValueList : dict.entrySet()) {
         StringDictEntry.Builder entry =
@@ -215,7 +241,6 @@
         builder.addStringDictValue(entry);
       }
     } else if (type == STRING_LIST_DICT) {
-      @SuppressWarnings("unchecked")
       Map<String, List<String>> dict = (Map<String, List<String>>) value;
       for (Map.Entry<String, List<String>> dictEntry : dict.entrySet()) {
         StringListDictEntry.Builder entry =
@@ -226,22 +251,20 @@
         builder.addStringListDictValue(entry);
       }
     } else if (type == LABEL_DICT_UNARY) {
-      @SuppressWarnings("unchecked")
       Map<String, Label> dict = (Map<String, Label>) value;
       for (Map.Entry<String, Label> dictEntry : dict.entrySet()) {
         LabelDictUnaryEntry.Builder entry =
             LabelDictUnaryEntry.newBuilder()
                 .setKey(dictEntry.getKey())
-                .setValue(dictEntry.getValue().toString());
+                .setValue(labelPrinter.toString(dictEntry.getValue()));
         builder.addLabelDictUnaryValue(entry);
       }
     } else if (type == LABEL_KEYED_STRING_DICT) {
-      @SuppressWarnings("unchecked")
       Map<Label, String> dict = (Map<Label, String>) value;
       for (Map.Entry<Label, String> dictEntry : dict.entrySet()) {
         LabelKeyedStringDictEntry.Builder entry =
             LabelKeyedStringDictEntry.newBuilder()
-                .setKey(dictEntry.getKey().toString())
+                .setKey(labelPrinter.toString(dictEntry.getKey()))
                 .setValue(dictEntry.getValue());
         builder.addLabelKeyedStringDictValue(entry);
       }
diff --git a/src/main/java/com/google/devtools/build/lib/packages/BUILD b/src/main/java/com/google/devtools/build/lib/packages/BUILD
index 8a1b4aa..66800ab 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/packages/BUILD
@@ -49,12 +49,14 @@
             "GlobberUtils.java",
             "ExecGroup.java",
             "ConfiguredAttributeMapper.java",
+            "LabelPrinter.java",
         ],
     ),
     deps = [
         ":exec_group",
         ":globber",
         ":globber_utils",
+        ":label_printer",
         "//src/main/java/com/google/devtools/build/docgen/annot",
         "//src/main/java/com/google/devtools/build/lib/actions:execution_requirements",
         "//src/main/java/com/google/devtools/build/lib/actions:thread_state_receiver",
@@ -133,3 +135,12 @@
         "//third_party:guava",
     ],
 )
+
+java_library(
+    name = "label_printer",
+    srcs = ["LabelPrinter.java"],
+    deps = [
+        "//src/main/java/com/google/devtools/build/lib/cmdline",
+        "//src/main/java/net/starlark/java/eval",
+    ],
+)
diff --git a/src/main/java/com/google/devtools/build/lib/packages/LabelPrinter.java b/src/main/java/com/google/devtools/build/lib/packages/LabelPrinter.java
new file mode 100644
index 0000000..43f0f8b
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/packages/LabelPrinter.java
@@ -0,0 +1,102 @@
+// Copyright 2022 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;
+
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.cmdline.PackageIdentifier;
+import com.google.devtools.build.lib.cmdline.RepositoryMapping;
+import net.starlark.java.eval.Printer;
+import net.starlark.java.eval.StarlarkSemantics;
+
+/** Knows how to print labels consistently in various formats. */
+public interface LabelPrinter {
+  /**
+   * Creates a {@link LabelPrinter} that prints labels in the same way as the Starlark `str` method.
+   * This behavior is useful when matching labels against Starlark values, in particular in tools.
+   *
+   * <p>Do not use this method directly, call {@link
+   * com.google.devtools.build.lib.query2.common.CommonQueryOptions#getLabelPrinter(StarlarkSemantics,
+   * RepositoryMapping)} instead.
+   */
+  static LabelPrinter starlark(StarlarkSemantics starlarkSemantics) {
+    return new LabelPrinter() {
+      @Override
+      public String toString(Label label) {
+        Printer printer = new Printer();
+        label.str(printer, starlarkSemantics);
+        return printer.toString();
+      }
+
+      @Override
+      public String toString(PackageIdentifier packageIdentifier) {
+        // PackageIdentifier is not a StarlarkValue and thus doesn't have a str method. Since it is
+        // only used in the context of --output=package, we reuse Label#str by stripping a
+        // placeholder name.
+        String label = toString(Label.createUnvalidated(packageIdentifier, "unused"));
+        return label.substring(0, label.length() - ":unused".length());
+      }
+    };
+  }
+
+  /**
+   * Creates a {@link LabelPrinter} that prints labels in a form meant for consumption by humans. It
+   * the main repository has visibility into the label's repository, the apparent repository name is
+   * used instead of the canonical repository name.
+   *
+   * <p>Do not use this method directly, call {@link
+   * com.google.devtools.build.lib.query2.common.CommonQueryOptions#getLabelPrinter(StarlarkSemantics,
+   * RepositoryMapping)} instead.
+   */
+  static LabelPrinter displayForm(RepositoryMapping mainRepoMapping) {
+    return new LabelPrinter() {
+      @Override
+      public String toString(Label label) {
+        return label.getDisplayForm(mainRepoMapping);
+      }
+
+      @Override
+      public String toString(PackageIdentifier packageIdentifier) {
+        return packageIdentifier.getDisplayForm(mainRepoMapping);
+      }
+    };
+  }
+
+  LabelPrinter LEGACY =
+      new LabelPrinter() {
+        @Override
+        public String toString(Label label) {
+          return label.toString();
+        }
+
+        @Override
+        public String toString(PackageIdentifier packageIdentifier) {
+          return packageIdentifier.toString();
+        }
+      };
+
+  /**
+   * Creates a {@link LabelPrinter} that prints labels via {@link Label#toString()}. This should
+   * only be used for backwards compatibility in cases where exact label forms matter, such as for
+   * genquery or in digests, or call sites outside of the query commands.
+   */
+  static LabelPrinter legacy() {
+    return LEGACY;
+  }
+
+  /** Returns a string representation of the given label. */
+  String toString(Label label);
+
+  String toString(PackageIdentifier packageIdentifier);
+}
diff --git a/src/main/java/com/google/devtools/build/lib/query2/BUILD b/src/main/java/com/google/devtools/build/lib/query2/BUILD
index 8316af8..6b47ee8 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/query2/BUILD
@@ -67,6 +67,7 @@
         "//src/main/java/com/google/devtools/build/lib/packages",
         "//src/main/java/com/google/devtools/build/lib/packages:configured_attribute_mapper",
         "//src/main/java/com/google/devtools/build/lib/packages:exec_group",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/pkgcache",
         "//src/main/java/com/google/devtools/build/lib/profiler",
         "//src/main/java/com/google/devtools/build/lib/profiler:google-auto-profiler-utils",
diff --git a/src/main/java/com/google/devtools/build/lib/query2/PostAnalysisQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/PostAnalysisQueryEnvironment.java
index 36e2574..79d1b12 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/PostAnalysisQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/PostAnalysisQueryEnvironment.java
@@ -28,7 +28,6 @@
 import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
 import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
 import com.google.devtools.build.lib.cmdline.TargetPattern;
 import com.google.devtools.build.lib.collect.compacthashset.CompactHashSet;
@@ -37,6 +36,7 @@
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.AspectClass;
 import com.google.devtools.build.lib.packages.DependencyFilter;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.packages.RuleTransitionData;
@@ -88,6 +88,7 @@
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import javax.annotation.Nullable;
+import net.starlark.java.eval.StarlarkSemantics;
 
 /**
  * {@link QueryEnvironment} that runs queries based on results from the analysis phase.
@@ -122,8 +123,9 @@
       TargetPattern.Parser mainRepoTargetParser,
       PathPackageLocator pkgPath,
       Supplier<WalkableGraph> walkableGraphSupplier,
-      Set<Setting> settings) {
-    super(keepGoing, true, Rule.ALL_LABELS, eventHandler, settings, extraFunctions);
+      Set<Setting> settings,
+      LabelPrinter labelPrinter) {
+    super(keepGoing, true, Rule.ALL_LABELS, eventHandler, settings, extraFunctions, labelPrinter);
     this.topLevelConfigurations = topLevelConfigurations;
     this.hostConfiguration = hostConfiguration;
     this.mainRepoTargetParser = mainRepoTargetParser;
@@ -139,7 +141,8 @@
           SkyframeExecutor skyframeExecutor,
           BuildConfigurationValue hostConfiguration,
           @Nullable TransitionFactory<RuleTransitionData> trimmingTransitionFactory,
-          PackageManager packageManager)
+          PackageManager packageManager,
+          StarlarkSemantics starlarkSemantics)
           throws QueryException, InterruptedException;
 
   public abstract String getOutputFormat();
@@ -253,8 +256,8 @@
   }
 
   @Override
-  public RepositoryMapping getMainRepoMapping() {
-    return mainRepoTargetParser.getRepoMapping();
+  public LabelPrinter getLabelPrinter() {
+    return labelPrinter;
   }
 
   public ThreadSafeMutableSet<T> getFwdDeps(Iterable<T> targets) throws InterruptedException {
diff --git a/src/main/java/com/google/devtools/build/lib/query2/QueryEnvironmentFactory.java b/src/main/java/com/google/devtools/build/lib/query2/QueryEnvironmentFactory.java
index be09bd4..9893f17 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/QueryEnvironmentFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/QueryEnvironmentFactory.java
@@ -19,6 +19,7 @@
 import com.google.devtools.build.lib.cmdline.TargetPattern;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.CachingPackageLocator;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
@@ -58,7 +59,8 @@
       Iterable<QueryFunction> extraFunctions,
       @Nullable PathPackageLocator packagePath,
       boolean blockUniverseEvaluationErrors,
-      boolean useGraphlessQuery) {
+      boolean useGraphlessQuery,
+      LabelPrinter labelPrinter) {
     Preconditions.checkNotNull(universeScope);
     if (canUseSkyQuery(orderedResults, universeScope, packagePath, strictScope, labelFilter)) {
       return new SkyQueryEnvironment(
@@ -72,7 +74,8 @@
           graphFactory,
           universeScope,
           packagePath,
-          blockUniverseEvaluationErrors);
+          blockUniverseEvaluationErrors,
+          labelPrinter);
     } else if (useGraphlessQuery) {
       return new GraphlessBlazeQueryEnvironment(
           queryTransitivePackagePreloader,
@@ -86,7 +89,8 @@
           labelFilter,
           eventHandler,
           settings,
-          extraFunctions);
+          extraFunctions,
+          labelPrinter);
     } else {
       return new BlazeQueryEnvironment(
           queryTransitivePackagePreloader,
@@ -100,7 +104,8 @@
           labelFilter,
           eventHandler,
           settings,
-          extraFunctions);
+          extraFunctions,
+          labelPrinter);
     }
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
index 744d035..0b62894 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
@@ -42,7 +42,6 @@
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.cmdline.ParallelVisitor.VisitTaskStatusCallback;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.cmdline.SignedTargetPattern;
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
 import com.google.devtools.build.lib.cmdline.TargetPattern;
@@ -57,6 +56,7 @@
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException;
 import com.google.devtools.build.lib.packages.DependencyFilter;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.NoSuchThingException;
@@ -183,13 +183,14 @@
       WalkableGraphFactory graphFactory,
       UniverseScope universeScope,
       PathPackageLocator pkgPath,
-      boolean blockUniverseEvaluationErrors) {
+      boolean blockUniverseEvaluationErrors,
+      LabelPrinter labelPrinter) {
     this(
         keepGoing,
         loadingPhaseThreads,
         // SkyQueryEnvironment operates on a prepopulated Skyframe graph. Therefore, query
         // evaluation is completely CPU-bound.
-        /*queryEvaluationParallelismLevel=*/ DEFAULT_THREAD_COUNT,
+        /* queryEvaluationParallelismLevel= */ DEFAULT_THREAD_COUNT,
         eventHandler,
         settings,
         extraFunctions,
@@ -198,7 +199,8 @@
         graphFactory,
         universeScope,
         pkgPath,
-        blockUniverseEvaluationErrors);
+        blockUniverseEvaluationErrors,
+        labelPrinter);
   }
 
   protected SkyQueryEnvironment(
@@ -213,14 +215,16 @@
       WalkableGraphFactory graphFactory,
       UniverseScope universeScope,
       PathPackageLocator pkgPath,
-      boolean blockUniverseEvaluationErrors) {
+      boolean blockUniverseEvaluationErrors,
+      LabelPrinter labelPrinter) {
     super(
         keepGoing,
-        /*strictScope=*/ true,
-        /*labelFilter=*/ Rule.ALL_LABELS,
+        /* strictScope= */ true,
+        /* labelFilter= */ Rule.ALL_LABELS,
         eventHandler,
         settings,
-        extraFunctions);
+        extraFunctions,
+        labelPrinter);
     this.loadingPhaseThreads = loadingPhaseThreads;
     this.graphFactory = graphFactory;
     this.pkgPath = pkgPath;
@@ -959,12 +963,6 @@
     return accessor;
   }
 
-  @Override
-  @ThreadSafe
-  public RepositoryMapping getMainRepoMapping() {
-    return mainRepoTargetParser.getRepoMapping();
-  }
-
   @ThreadSafe
   private Package getPackage(PackageIdentifier packageIdentifier)
       throws InterruptedException, QueryException, NoSuchPackageException {
diff --git a/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphQueryEnvironment.java
index dd2d5ce..45b32a7 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphQueryEnvironment.java
@@ -28,6 +28,7 @@
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
 import com.google.devtools.build.lib.cmdline.TargetPattern;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.RuleTransitionData;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.pkgcache.PackageManager;
@@ -55,6 +56,7 @@
 import java.util.Set;
 import java.util.function.Supplier;
 import javax.annotation.Nullable;
+import net.starlark.java.eval.StarlarkSemantics;
 
 /**
  * {@link QueryEnvironment} that is specialized for running action graph queries over the configured
@@ -81,7 +83,8 @@
       TargetPattern.Parser mainRepoTargetParser,
       PathPackageLocator pkgPath,
       Supplier<WalkableGraph> walkableGraphSupplier,
-      Set<Setting> settings) {
+      Set<Setting> settings,
+      LabelPrinter labelPrinter) {
     super(
         keepGoing,
         eventHandler,
@@ -91,7 +94,8 @@
         mainRepoTargetParser,
         pkgPath,
         walkableGraphSupplier,
-        settings);
+        settings,
+        labelPrinter);
     this.configuredTargetKeyExtractor = KeyedConfiguredTargetValue::getConfiguredTargetKey;
     this.accessor =
         new ConfiguredTargetValueAccessor(
@@ -107,7 +111,8 @@
       TargetPattern.Parser mainRepoTargetParser,
       PathPackageLocator pkgPath,
       Supplier<WalkableGraph> walkableGraphSupplier,
-      AqueryOptions aqueryOptions) {
+      AqueryOptions aqueryOptions,
+      LabelPrinter labelPrinter) {
     this(
         keepGoing,
         eventHandler,
@@ -117,7 +122,8 @@
         mainRepoTargetParser,
         pkgPath,
         walkableGraphSupplier,
-        aqueryOptions.toSettings());
+        aqueryOptions.toSettings(),
+        labelPrinter);
     this.aqueryOptions = aqueryOptions;
   }
 
@@ -143,7 +149,8 @@
           SkyframeExecutor skyframeExecutor,
           BuildConfigurationValue hostConfiguration,
           @Nullable TransitionFactory<RuleTransitionData> trimmingTransitionFactory,
-          PackageManager packageManager) {
+          PackageManager packageManager,
+          StarlarkSemantics starlarkSemantics) {
     return ImmutableList.of(
         new ActionGraphProtoOutputFormatterCallback(
             eventHandler,
@@ -176,7 +183,7 @@
             skyframeExecutor,
             accessor,
             actionFilters,
-            getMainRepoMapping()),
+            getLabelPrinter()),
         new ActionGraphSummaryOutputFormatterCallback(
             eventHandler, aqueryOptions, out, skyframeExecutor, accessor, actionFilters));
   }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphTextOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphTextOutputFormatterCallback.java
index b98ecc3..6e95435 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphTextOutputFormatterCallback.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphTextOutputFormatterCallback.java
@@ -38,9 +38,9 @@
 import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction;
 import com.google.devtools.build.lib.buildeventstream.BuildEvent;
 import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.AspectDescriptor;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.query2.engine.QueryEnvironment.TargetAccessor;
 import com.google.devtools.build.lib.skyframe.RuleConfiguredTargetValue;
 import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
@@ -63,7 +63,7 @@
 
   private final ActionKeyContext actionKeyContext = new ActionKeyContext();
   private final AqueryActionFilter actionFilters;
-  private final RepositoryMapping mainRepoMapping;
+  private final LabelPrinter labelPrinter;
   private Map<String, String> paramFileNameToContentMap;
 
   ActionGraphTextOutputFormatterCallback(
@@ -73,10 +73,10 @@
       SkyframeExecutor skyframeExecutor,
       TargetAccessor<KeyedConfiguredTargetValue> accessor,
       AqueryActionFilter actionFilters,
-      RepositoryMapping mainRepoMapping) {
+      LabelPrinter labelPrinter) {
     super(eventHandler, options, out, skyframeExecutor, accessor);
     this.actionFilters = actionFilters;
-    this.mainRepoMapping = mainRepoMapping;
+    this.labelPrinter = labelPrinter;
   }
 
   @Override
@@ -149,7 +149,7 @@
 
       stringBuilder
           .append("  Target: ")
-          .append(actionOwner.getLabel().getDisplayForm(mainRepoMapping))
+          .append(labelPrinter.toString(actionOwner.getLabel()))
           .append('\n')
           .append("  Configuration: ")
           .append(configProto.getMnemonic())
@@ -157,7 +157,7 @@
       if (actionOwner.getExecutionPlatform() != null) {
         stringBuilder
             .append("  Execution platform: ")
-            .append(actionOwner.getExecutionPlatform().label().getDisplayForm(mainRepoMapping))
+            .append(labelPrinter.toString(actionOwner.getExecutionPlatform().label()))
             .append("\n");
       }
 
diff --git a/src/main/java/com/google/devtools/build/lib/query2/common/AbstractBlazeQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/common/AbstractBlazeQueryEnvironment.java
index e5a60bd..a2678d5 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/common/AbstractBlazeQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/common/AbstractBlazeQueryEnvironment.java
@@ -35,6 +35,7 @@
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.DependencyFilter;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.profiler.Profiler;
 import com.google.devtools.build.lib.profiler.SilentCloseable;
@@ -85,6 +86,7 @@
 
   protected final Set<Setting> settings;
   protected final List<QueryFunction> extraFunctions;
+  protected final LabelPrinter labelPrinter;
 
   protected AbstractBlazeQueryEnvironment(
       boolean keepGoing,
@@ -92,7 +94,8 @@
       Predicate<Label> labelFilter,
       ExtendedEventHandler eventHandler,
       Set<Setting> settings,
-      Iterable<QueryFunction> extraFunctions) {
+      Iterable<QueryFunction> extraFunctions,
+      LabelPrinter labelPrinter) {
     this.eventHandler = new ErrorSensingEventHandler<>(eventHandler, DetailedExitCode.class);
     this.keepGoing = keepGoing;
     this.strictScope = strictScope;
@@ -100,11 +103,17 @@
     this.labelFilter = labelFilter;
     this.settings = Sets.immutableEnumSet(settings);
     this.extraFunctions = ImmutableList.copyOf(extraFunctions);
+    this.labelPrinter = labelPrinter;
   }
 
   @Override
   public abstract void close();
 
+  @Override
+  public LabelPrinter getLabelPrinter() {
+    return labelPrinter;
+  }
+
   private static DependencyFilter constructDependencyFilter(Set<Setting> settings) {
     DependencyFilter specifiedFilter =
         settings.contains(Setting.ONLY_TARGET_DEPS)
diff --git a/src/main/java/com/google/devtools/build/lib/query2/common/BUILD b/src/main/java/com/google/devtools/build/lib/query2/common/BUILD
index 110aa50..f0be274 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/common/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/query2/common/BUILD
@@ -18,6 +18,7 @@
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/events",
         "//src/main/java/com/google/devtools/build/lib/packages",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/profiler",
         "//src/main/java/com/google/devtools/build/lib/query2/engine",
         "//src/main/java/com/google/devtools/build/lib/util:detailed_exit_code",
@@ -35,9 +36,12 @@
         "FlagConstants.java",
     ],
     deps = [
+        "//src/main/java/com/google/devtools/build/lib/cmdline",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/query2/engine",
         "//src/main/java/com/google/devtools/build/lib/query2/query/aspectresolvers",
         "//src/main/java/com/google/devtools/common/options",
+        "//src/main/java/net/starlark/java/eval",
         "//third_party:guava",
     ],
 )
diff --git a/src/main/java/com/google/devtools/build/lib/query2/common/CommonQueryOptions.java b/src/main/java/com/google/devtools/build/lib/query2/common/CommonQueryOptions.java
index 693c88f..a3fe5e7 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/common/CommonQueryOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/common/CommonQueryOptions.java
@@ -14,6 +14,8 @@
 package com.google.devtools.build.lib.query2.common;
 
 import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.cmdline.RepositoryMapping;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.query2.engine.QueryEnvironment.Setting;
 import com.google.devtools.build.lib.query2.query.aspectresolvers.AspectResolver;
 import com.google.devtools.build.lib.query2.query.aspectresolvers.AspectResolver.Mode;
@@ -28,6 +30,7 @@
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Set;
+import net.starlark.java.eval.StarlarkSemantics;
 
 /** Options shared between blaze query implementations. */
 public class CommonQueryOptions extends OptionsBase {
@@ -166,6 +169,27 @@
     return settings;
   }
 
+  @Option(
+      name = "consistent_labels",
+      defaultValue = "false",
+      documentationCategory = OptionDocumentationCategory.QUERY,
+      effectTags = {OptionEffectTag.TERMINAL_OUTPUT},
+      help =
+          "If enabled, every query command emits labels as if by the Starlark <code>str</code>"
+              + " function applied to a <code>Label</code> instance. This is useful for tools that"
+              + " need to match the output of different query commands and/or labels emitted by"
+              + " rules. If not enabled, output formatters are free to emit apparent repository"
+              + " names (relative to the main repository) instead to make the output more"
+              + " readable.")
+  public boolean emitConsistentLabels;
+
+  public LabelPrinter getLabelPrinter(
+      StarlarkSemantics starlarkSemantics, RepositoryMapping mainRepoMapping) {
+    return emitConsistentLabels
+        ? LabelPrinter.starlark(starlarkSemantics)
+        : LabelPrinter.displayForm(mainRepoMapping);
+  }
+
   ///////////////////////////////////////////////////////////
   // LOCATION OUTPUT FORMATTER OPTIONS                     //
   ///////////////////////////////////////////////////////////
diff --git a/src/main/java/com/google/devtools/build/lib/query2/cquery/BuildOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/cquery/BuildOutputFormatterCallback.java
index 0a8944f..a9fc05c 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/cquery/BuildOutputFormatterCallback.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/cquery/BuildOutputFormatterCallback.java
@@ -19,6 +19,7 @@
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.ConfiguredAttributeMapper;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.query2.engine.QueryEnvironment.TargetAccessor;
@@ -32,13 +33,18 @@
 
 /** Cquery implementation of BUILD-style output. */
 class BuildOutputFormatterCallback extends CqueryThreadsafeCallback {
+
+  private final LabelPrinter labelPrinter;
+
   BuildOutputFormatterCallback(
       ExtendedEventHandler eventHandler,
       CqueryOptions options,
       OutputStream out,
       SkyframeExecutor skyframeExecutor,
-      TargetAccessor<KeyedConfiguredTarget> accessor) {
-    super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ false);
+      TargetAccessor<KeyedConfiguredTarget> accessor,
+      LabelPrinter labelPrinter) {
+    super(eventHandler, options, out, skyframeExecutor, accessor, /* uniquifyResults= */ false);
+    this.labelPrinter = labelPrinter;
   }
 
   @Override
@@ -97,7 +103,8 @@
             // selects. Going forward we could expand this to show both the complete select
             // and which path is chosen, which people may find even more informative.
             (rule, attr) -> false,
-            System.lineSeparator());
+            System.lineSeparator(),
+            labelPrinter);
     for (KeyedConfiguredTarget configuredTarget : partialResult) {
       Target target = accessor.getTarget(configuredTarget);
       outputter.output(target, new CqueryAttributeReader(getAttributeMap(configuredTarget)));
diff --git a/src/main/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryEnvironment.java
index 22fa145..561d0c8 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryEnvironment.java
@@ -33,6 +33,7 @@
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
 import com.google.devtools.build.lib.cmdline.TargetPattern;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.RuleTransitionData;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.pkgcache.PackageManager;
@@ -63,6 +64,7 @@
 import java.util.function.Function;
 import java.util.function.Supplier;
 import javax.annotation.Nullable;
+import net.starlark.java.eval.StarlarkSemantics;
 
 /**
  * {@link QueryEnvironment} that runs queries over the configured target (analysis) graph.
@@ -121,7 +123,8 @@
       PathPackageLocator pkgPath,
       Supplier<WalkableGraph> walkableGraphSupplier,
       Set<Setting> settings,
-      TopLevelArtifactContext topLevelArtifactContext)
+      TopLevelArtifactContext topLevelArtifactContext,
+      LabelPrinter labelPrinter)
       throws InterruptedException {
     super(
         keepGoing,
@@ -132,7 +135,8 @@
         mainRepoTargetParser,
         pkgPath,
         walkableGraphSupplier,
-        settings);
+        settings,
+        labelPrinter);
     this.accessor = new ConfiguredTargetAccessor(walkableGraphSupplier.get(), this);
     this.configuredTargetKeyExtractor = KeyedConfiguredTarget::getConfiguredTargetKey;
     this.transitiveConfigurations =
@@ -151,7 +155,8 @@
       PathPackageLocator pkgPath,
       Supplier<WalkableGraph> walkableGraphSupplier,
       CqueryOptions cqueryOptions,
-      TopLevelArtifactContext topLevelArtifactContext)
+      TopLevelArtifactContext topLevelArtifactContext,
+      LabelPrinter labelPrinter)
       throws InterruptedException {
     this(
         keepGoing,
@@ -164,7 +169,8 @@
         pkgPath,
         walkableGraphSupplier,
         cqueryOptions.toSettings(),
-        topLevelArtifactContext);
+        topLevelArtifactContext,
+        labelPrinter);
     this.cqueryOptions = cqueryOptions;
   }
 
@@ -199,27 +205,16 @@
           SkyframeExecutor skyframeExecutor,
           BuildConfigurationValue hostConfiguration,
           @Nullable TransitionFactory<RuleTransitionData> trimmingTransitionFactory,
-          PackageManager packageManager)
+          PackageManager packageManager,
+          StarlarkSemantics starlarkSemantics)
           throws QueryException, InterruptedException {
     AspectResolver aspectResolver =
         cqueryOptions.aspectDeps.createResolver(packageManager, eventHandler);
     return ImmutableList.of(
         new LabelAndConfigurationOutputFormatterCallback(
-            eventHandler,
-            cqueryOptions,
-            out,
-            skyframeExecutor,
-            accessor,
-            true,
-            getMainRepoMapping()),
+            eventHandler, cqueryOptions, out, skyframeExecutor, accessor, true, getLabelPrinter()),
         new LabelAndConfigurationOutputFormatterCallback(
-            eventHandler,
-            cqueryOptions,
-            out,
-            skyframeExecutor,
-            accessor,
-            false,
-            getMainRepoMapping()),
+            eventHandler, cqueryOptions, out, skyframeExecutor, accessor, false, getLabelPrinter()),
         new TransitionsOutputFormatterCallback(
             eventHandler,
             cqueryOptions,
@@ -228,7 +223,7 @@
             accessor,
             hostConfiguration,
             trimmingTransitionFactory,
-            getMainRepoMapping()),
+            getLabelPrinter()),
         new ProtoOutputFormatterCallback(
             eventHandler,
             cqueryOptions,
@@ -237,7 +232,8 @@
             accessor,
             aspectResolver,
             OutputType.BINARY,
-            trimmingTransitionFactory),
+            trimmingTransitionFactory,
+            getLabelPrinter()),
         new ProtoOutputFormatterCallback(
             eventHandler,
             cqueryOptions,
@@ -246,7 +242,8 @@
             accessor,
             aspectResolver,
             OutputType.TEXT,
-            trimmingTransitionFactory),
+            trimmingTransitionFactory,
+            getLabelPrinter()),
         new ProtoOutputFormatterCallback(
             eventHandler,
             cqueryOptions,
@@ -255,9 +252,10 @@
             accessor,
             aspectResolver,
             OutputType.JSON,
-            trimmingTransitionFactory),
+            trimmingTransitionFactory,
+            getLabelPrinter()),
         new BuildOutputFormatterCallback(
-            eventHandler, cqueryOptions, out, skyframeExecutor, accessor),
+            eventHandler, cqueryOptions, out, skyframeExecutor, accessor, getLabelPrinter()),
         new GraphOutputFormatterCallback(
             eventHandler,
             cqueryOptions,
@@ -265,9 +263,9 @@
             skyframeExecutor,
             accessor,
             kct -> getFwdDeps(ImmutableList.of(kct)),
-            getMainRepoMapping()),
+            getLabelPrinter()),
         new StarlarkOutputFormatterCallback(
-            eventHandler, cqueryOptions, out, skyframeExecutor, accessor),
+            eventHandler, cqueryOptions, out, skyframeExecutor, accessor, starlarkSemantics),
         new FilesOutputFormatterCallback(
             eventHandler, cqueryOptions, out, skyframeExecutor, accessor, topLevelArtifactContext));
   }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/cquery/GraphOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/cquery/GraphOutputFormatterCallback.java
index 009fcd4..3908e67 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/cquery/GraphOutputFormatterCallback.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/cquery/GraphOutputFormatterCallback.java
@@ -16,10 +16,10 @@
 
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.graph.Digraph;
 import com.google.devtools.build.lib.graph.Node;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.query2.engine.QueryEnvironment.TargetAccessor;
 import com.google.devtools.build.lib.query2.query.output.GraphOutputWriter;
 import com.google.devtools.build.lib.query2.query.output.GraphOutputWriter.NodeReader;
@@ -66,14 +66,13 @@
             };
 
         @Override
-        public String getLabel(
-            Node<KeyedConfiguredTarget> node, RepositoryMapping mainRepositoryMapping) {
+        public String getLabel(Node<KeyedConfiguredTarget> node, LabelPrinter labelPrinter) {
           // Node payloads are ConfiguredTargets. Output node labels are target labels + config
           // hashes.
           KeyedConfiguredTarget kct = node.getLabel();
           return String.format(
               "%s (%s)",
-              kct.getLabel().getDisplayForm(mainRepositoryMapping),
+              labelPrinter.toString(kct.getLabel()),
               shortId(getConfiguration(kct.getConfigurationKey())));
         }
 
@@ -83,7 +82,7 @@
         }
       };
 
-  private final RepositoryMapping mainRepoMapping;
+  private final LabelPrinter labelPrinter;
 
   GraphOutputFormatterCallback(
       ExtendedEventHandler eventHandler,
@@ -92,10 +91,10 @@
       SkyframeExecutor skyframeExecutor,
       TargetAccessor<KeyedConfiguredTarget> accessor,
       DepsRetriever depsRetriever,
-      RepositoryMapping mainRepoMapping) {
-    super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ false);
+      LabelPrinter labelPrinter) {
+    super(eventHandler, options, out, skyframeExecutor, accessor, /* uniquifyResults= */ false);
     this.depsRetriever = depsRetriever;
-    this.mainRepoMapping = mainRepoMapping;
+    this.labelPrinter = labelPrinter;
   }
 
   @Override
@@ -126,7 +125,7 @@
             // phase, when select()s have been resolved and removed from the graph.
             /*maxConditionalEdges=*/ 0,
             options.graphFactored,
-            mainRepoMapping);
+            labelPrinter);
     graphWriter.write(graph, /*conditionalEdges=*/ null, outputStream);
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/cquery/LabelAndConfigurationOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/cquery/LabelAndConfigurationOutputFormatterCallback.java
index 73bfd9c..91b5b80 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/cquery/LabelAndConfigurationOutputFormatterCallback.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/cquery/LabelAndConfigurationOutputFormatterCallback.java
@@ -18,8 +18,8 @@
 import com.google.devtools.build.lib.analysis.RequiredConfigFragmentsProvider;
 import com.google.devtools.build.lib.analysis.config.CoreOptions.IncludeConfigFragmentsEnum;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.query2.engine.QueryEnvironment.TargetAccessor;
 import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
@@ -29,7 +29,7 @@
 /** Default Output callback for cquery. Prints a label and configuration pair per result. */
 public class LabelAndConfigurationOutputFormatterCallback extends CqueryThreadsafeCallback {
   private final boolean showKind;
-  private final RepositoryMapping mainRepoMapping;
+  private final LabelPrinter labelPrinter;
 
   LabelAndConfigurationOutputFormatterCallback(
       ExtendedEventHandler eventHandler,
@@ -38,10 +38,10 @@
       SkyframeExecutor skyframeExecutor,
       TargetAccessor<KeyedConfiguredTarget> accessor,
       boolean showKind,
-      RepositoryMapping mainRepoMapping) {
-    super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ false);
+      LabelPrinter labelPrinter) {
+    super(eventHandler, options, out, skyframeExecutor, accessor, /* uniquifyResults= */ false);
     this.showKind = showKind;
-    this.mainRepoMapping = mainRepoMapping;
+    this.labelPrinter = labelPrinter;
   }
 
   @Override
@@ -59,7 +59,7 @@
       }
       output =
           output
-              .append(keyedConfiguredTarget.getLabel().getDisplayForm(mainRepoMapping))
+              .append(labelPrinter.toString(keyedConfiguredTarget.getLabel()))
               .append(" (")
               .append(shortId(getConfiguration(keyedConfiguredTarget.getConfigurationKey())))
               .append(")");
diff --git a/src/main/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallback.java
index db7b1f7..028bf57 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallback.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallback.java
@@ -34,6 +34,7 @@
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.AttributeFormatter;
 import com.google.devtools.build.lib.packages.ConfiguredAttributeMapper;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.packages.RuleTransitionData;
 import com.google.devtools.build.lib.packages.Target;
@@ -114,6 +115,7 @@
   private AnalysisProtosV2.CqueryResult.Builder protoResult;
 
   private final Map<Label, Target> partialResultMap;
+  private final LabelPrinter labelPrinter;
   private KeyedConfiguredTarget currentTarget;
 
   ProtoOutputFormatterCallback(
@@ -124,13 +126,15 @@
       TargetAccessor<KeyedConfiguredTarget> accessor,
       AspectResolver resolver,
       OutputType outputType,
-      @Nullable TransitionFactory<RuleTransitionData> trimmingTransitionFactory) {
+      @Nullable TransitionFactory<RuleTransitionData> trimmingTransitionFactory,
+      LabelPrinter labelPrinter) {
     super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ false);
     this.outputType = outputType;
     this.skyframeExecutor = skyframeExecutor;
     this.resolver = resolver;
     this.trimmingTransitionFactory = trimmingTransitionFactory;
     this.partialResultMap = Maps.newHashMap();
+    this.labelPrinter = labelPrinter;
   }
 
   @Override
@@ -211,7 +215,8 @@
       // we will want to add relevant tests.
       currentTarget = keyedConfiguredTarget;
       Target target = accessor.getTarget(keyedConfiguredTarget);
-      Build.Target.Builder targetBuilder = formatter.toTargetProtoBuffer(target).toBuilder();
+      Build.Target.Builder targetBuilder =
+          formatter.toTargetProtoBuffer(target, labelPrinter).toBuilder();
       if (target instanceof Rule && !Transitions.NONE.equals(options.transitions)) {
         try {
           for (CqueryTransitionResolver.ResolvedTransition resolvedTransition :
@@ -221,7 +226,7 @@
                   .getRuleBuilder()
                   .addConfiguredRuleInput(
                       Build.ConfiguredRuleInput.newBuilder()
-                          .setLabel(resolvedTransition.label().toString()));
+                          .setLabel(labelPrinter.toString(resolvedTransition.label())));
             } else {
               for (BuildOptions options : resolvedTransition.options()) {
                 BuildConfigurationEvent buildConfigurationEvent =
@@ -233,7 +238,7 @@
                     .getRuleBuilder()
                     .addConfiguredRuleInput(
                         Build.ConfiguredRuleInput.newBuilder()
-                            .setLabel(resolvedTransition.label().toString())
+                            .setLabel(labelPrinter.toString(resolvedTransition.label()))
                             .setConfigurationChecksum(options.checksum())
                             .setConfigurationId(configurationId));
               }
@@ -271,7 +276,10 @@
   private class ConfiguredProtoOutputFormatter extends ProtoOutputFormatter {
     @Override
     protected void addAttributes(
-        Build.Rule.Builder rulePb, Rule rule, Object extraDataForAttrHash) {
+        Build.Rule.Builder rulePb,
+        Rule rule,
+        Object extraDataForAttrHash,
+        LabelPrinter labelPrinter) {
       // We know <code>currentTarget</code> will be either an AliasConfiguredTarget or
       // RuleConfiguredTarget,
       // because this method is only triggered in ProtoOutputFormatter.toTargetProtoBuffer when
@@ -294,7 +302,8 @@
                 attr,
                 attributeValue,
                 rule.isAttributeValueExplicitlySpecified(attr),
-                /*encodeBooleanAndTriStateAsIntegerAndString=*/ true);
+                /* encodeBooleanAndTriStateAsIntegerAndString= */ true,
+                labelPrinter);
         rulePb.addAttribute(serializedAttribute);
       }
     }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/cquery/StarlarkOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/cquery/StarlarkOutputFormatterCallback.java
index d107529..38dd310 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/cquery/StarlarkOutputFormatterCallback.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/cquery/StarlarkOutputFormatterCallback.java
@@ -132,15 +132,18 @@
 
   // Starlark function with single required parameter "target", a ConfiguredTarget query result.
   private final StarlarkFunction formatFn;
+  private final StarlarkSemantics starlarkSemantics;
 
   StarlarkOutputFormatterCallback(
       ExtendedEventHandler eventHandler,
       CqueryOptions options,
       OutputStream out,
       SkyframeExecutor skyframeExecutor,
-      TargetAccessor<KeyedConfiguredTarget> accessor)
+      TargetAccessor<KeyedConfiguredTarget> accessor,
+      StarlarkSemantics starlarkSemantics)
       throws QueryException, InterruptedException {
-    super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ false);
+    super(eventHandler, options, out, skyframeExecutor, accessor, /* uniquifyResults= */ false);
+    this.starlarkSemantics = starlarkSemantics;
 
     ParserInput input = null;
     String exceptionMessagePrefix;
@@ -183,12 +186,12 @@
     }
     try (Mutability mu = Mutability.create("formatter")) {
       ImmutableMap.Builder<String, Object> env = ImmutableMap.builder();
-      Starlark.addMethods(env, new CqueryDialectGlobals(), StarlarkSemantics.DEFAULT);
+      Starlark.addMethods(env, new CqueryDialectGlobals(), starlarkSemantics);
       env.putAll(StarlarkLibrary.COMMON);
       env.put("struct", StructProvider.STRUCT);
-      Module module = Module.withPredeclared(StarlarkSemantics.DEFAULT, env.buildOrThrow());
+      Module module = Module.withPredeclared(starlarkSemantics, env.buildOrThrow());
 
-      StarlarkThread thread = new StarlarkThread(mu, StarlarkSemantics.DEFAULT);
+      StarlarkThread thread = new StarlarkThread(mu, starlarkSemantics);
       Starlark.execFile(input, FileOptions.DEFAULT, module, thread);
       Object formatFn = module.getGlobal("format");
       if (formatFn == null) {
@@ -231,7 +234,7 @@
     for (KeyedConfiguredTarget target : partialResult) {
       try {
         StarlarkThread thread =
-            new StarlarkThread(Mutability.create("cquery evaluation"), StarlarkSemantics.DEFAULT);
+            new StarlarkThread(Mutability.create("cquery evaluation"), starlarkSemantics);
         thread.setMaxExecutionSteps(500_000L);
 
         // Invoke formatFn with `target` argument.
diff --git a/src/main/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterCallback.java
index e3dc119..1075529 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterCallback.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterCallback.java
@@ -27,9 +27,9 @@
 import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
 import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.RuleTransitionData;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.query2.cquery.CqueryTransitionResolver.ResolvedTransition;
@@ -49,7 +49,7 @@
 
   private final HashMap<Label, Target> partialResultMap;
   @Nullable private final TransitionFactory<RuleTransitionData> trimmingTransitionFactory;
-  private final RepositoryMapping mainRepoMapping;
+  private final LabelPrinter labelPrinter;
 
   @Override
   public String getName() {
@@ -68,12 +68,12 @@
       TargetAccessor<KeyedConfiguredTarget> accessor,
       BuildConfigurationValue hostConfiguration,
       @Nullable TransitionFactory<RuleTransitionData> trimmingTransitionFactory,
-      RepositoryMapping mainRepoMapping) {
-    super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ false);
+      LabelPrinter labelPrinter) {
+    super(eventHandler, options, out, skyframeExecutor, accessor, /* uniquifyResults= */ false);
     this.hostConfiguration = hostConfiguration;
     this.trimmingTransitionFactory = trimmingTransitionFactory;
     this.partialResultMap = Maps.newHashMap();
-    this.mainRepoMapping = mainRepoMapping;
+    this.labelPrinter = labelPrinter;
   }
 
   @Override
@@ -96,10 +96,10 @@
           getRuleClassTransition(keyedConfiguredTarget.getConfiguredTarget(), target)
               + String.format(
                   "%s (%s)",
-                  keyedConfiguredTarget
+                  labelPrinter.toString(keyedConfiguredTarget
                       .getConfiguredTarget()
                       .getOriginalLabel()
-                      .getDisplayForm(mainRepoMapping),
+                      ),
                   shortId(config)));
       KnownTargetsDependencyResolver knownTargetsDependencyResolver =
           new KnownTargetsDependencyResolver(partialResultMap);
@@ -125,7 +125,7 @@
             "  "
                 .concat(dep.attributeName())
                 .concat("#")
-                .concat(dep.label().getDisplayForm(mainRepoMapping))
+                .concat(labelPrinter.toString(dep.label()))
                 .concat("#")
                 .concat(dep.transitionName())
                 .concat(" -> ")
diff --git a/src/main/java/com/google/devtools/build/lib/query2/engine/BUILD b/src/main/java/com/google/devtools/build/lib/query2/engine/BUILD
index c70b8e0..03a0d78 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/engine/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/query2/engine/BUILD
@@ -19,6 +19,7 @@
         "//src/main/java/com/google/devtools/build/lib/concurrent",
         "//src/main/java/com/google/devtools/build/lib/graph",
         "//src/main/java/com/google/devtools/build/lib/packages",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/profiler",
         "//src/main/java/com/google/devtools/build/lib/util:detailed_exit_code",
         "//src/main/protobuf:failure_details_java_proto",
diff --git a/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java
index 3aa9ca4..666359d 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java
@@ -19,8 +19,8 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.util.DetailedExitCode;
 import java.util.Collection;
@@ -537,12 +537,7 @@
    */
   TargetAccessor<T> getAccessor();
 
-  /**
-   * Returns the {@link RepositoryMapping} of the main repository so that output formatters can
-   * resolve canonical repository names in labels back to the more readable local names used by the
-   * main repository.
-   */
-  RepositoryMapping getMainRepoMapping();
+  LabelPrinter getLabelPrinter();
 
   /**
    * Whether the given setting is enabled. The code should default to return {@code false} for all
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/BlazeQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/query/BlazeQueryEnvironment.java
index 16165de..ee72a3e 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/BlazeQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/BlazeQueryEnvironment.java
@@ -20,7 +20,6 @@
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
 import com.google.devtools.build.lib.cmdline.TargetPattern;
 import com.google.devtools.build.lib.cmdline.TargetPattern.Parser;
@@ -31,6 +30,7 @@
 import com.google.devtools.build.lib.graph.Node;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.CachingPackageLocator;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.NoSuchThingException;
 import com.google.devtools.build.lib.packages.OutputFile;
 import com.google.devtools.build.lib.packages.Package;
@@ -118,8 +118,10 @@
       Predicate<Label> labelFilter,
       ExtendedEventHandler eventHandler,
       Set<Setting> settings,
-      Iterable<QueryFunction> extraFunctions) {
-    super(keepGoing, strictScope, labelFilter, eventHandler, settings, extraFunctions);
+      Iterable<QueryFunction> extraFunctions,
+      LabelPrinter labelPrinter) {
+    super(
+        keepGoing, strictScope, labelFilter, eventHandler, settings, extraFunctions, labelPrinter);
     this.targetPatternPreloader = targetPatternPreloader;
     this.mainRepoTargetParser = mainRepoTargetParser;
     this.queryTransitivePackagePreloader = queryTransitivePackagePreloader;
@@ -501,11 +503,6 @@
     return accessor;
   }
 
-  @Override
-  public RepositoryMapping getMainRepoMapping() {
-    return mainRepoTargetParser.getRepoMapping();
-  }
-
   /** Given a set of target nodes, returns the targets. */
   private ThreadSafeMutableSet<Target> getTargetsFromNodes(Iterable<Node<Target>> input) {
     ThreadSafeMutableSet<Target> result = createThreadSafeMutableSet();
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/GraphlessBlazeQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/query/GraphlessBlazeQueryEnvironment.java
index a83a8aa..389623c 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/GraphlessBlazeQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/GraphlessBlazeQueryEnvironment.java
@@ -17,7 +17,6 @@
 import com.google.common.collect.Sets;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
 import com.google.devtools.build.lib.cmdline.TargetPattern;
 import com.google.devtools.build.lib.cmdline.TargetPattern.Parser;
@@ -26,6 +25,7 @@
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.CachingPackageLocator;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.NoSuchThingException;
 import com.google.devtools.build.lib.packages.Package;
 import com.google.devtools.build.lib.packages.Target;
@@ -121,8 +121,10 @@
       Predicate<Label> labelFilter,
       ExtendedEventHandler eventHandler,
       Set<Setting> settings,
-      Iterable<QueryFunction> extraFunctions) {
-    super(keepGoing, strictScope, labelFilter, eventHandler, settings, extraFunctions);
+      Iterable<QueryFunction> extraFunctions,
+      LabelPrinter labelPrinter) {
+    super(
+        keepGoing, strictScope, labelFilter, eventHandler, settings, extraFunctions, labelPrinter);
     this.targetPatternPreloader = targetPatternPreloader;
     this.mainRepoTargetParser = mainRepoTargetParser;
     this.queryTransitivePackagePreloader = queryTransitivePackagePreloader;
@@ -508,9 +510,4 @@
   public TargetAccessor<Target> getAccessor() {
     return accessor;
   }
-
-  @Override
-  public RepositoryMapping getMainRepoMapping() {
-    return mainRepoTargetParser.getRepoMapping();
-  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/AbstractUnorderedFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/AbstractUnorderedFormatter.java
index 6cc6a95..7a01979 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/AbstractUnorderedFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/AbstractUnorderedFormatter.java
@@ -16,10 +16,10 @@
 
 import com.google.common.collect.Iterables;
 import com.google.common.hash.HashFunction;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.graph.Digraph;
 import com.google.devtools.build.lib.graph.Node;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.query2.common.CommonQueryOptions;
 import com.google.devtools.build.lib.query2.engine.OutputFormatterCallback;
@@ -47,12 +47,12 @@
       AspectResolver aspectResolver,
       @Nullable EventHandler eventHandler,
       HashFunction hashFunction,
-      RepositoryMapping mainRepoMapping)
+      LabelPrinter labelPrinter)
       throws IOException, InterruptedException {
     setOptions(options, aspectResolver, hashFunction);
     setEventHandler(eventHandler);
     OutputFormatterCallback.processAllTargets(
-        createPostFactoStreamCallback(out, options, mainRepoMapping),
+        createPostFactoStreamCallback(out, options, labelPrinter),
         getOrderedTargets(result, options));
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/BUILD b/src/main/java/com/google/devtools/build/lib/query2/query/output/BUILD
index 861d484..d2230a1 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/BUILD
@@ -18,6 +18,7 @@
         "//src/main/java/com/google/devtools/build/lib/events",
         "//src/main/java/com/google/devtools/build/lib/graph",
         "//src/main/java/com/google/devtools/build/lib/packages",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/profiler",
         "//src/main/java/com/google/devtools/build/lib/query2/common:abstract-blaze-query-env",
         "//src/main/java/com/google/devtools/build/lib/query2/common:options",
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/BuildOutputFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/BuildOutputFormatter.java
index 46fed49..188f920 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/BuildOutputFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/BuildOutputFormatter.java
@@ -17,10 +17,10 @@
 import com.google.common.base.Ascii;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.collect.compacthashset.CompactHashSet;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.BuildType;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.License;
 import com.google.devtools.build.lib.packages.RawAttributeMapper;
 import com.google.devtools.build.lib.packages.Rule;
@@ -65,6 +65,7 @@
     private final Writer writer;
     private final BiPredicate<Rule, Attribute> preserveSelect;
     private final String lineTerm;
+    private final LabelPrinter labelPrinter;
     private final Set<Label> printed = CompactHashSet.create();
 
     /**
@@ -75,10 +76,14 @@
      * @param lineTerm character to add to the end of each line
      */
     public TargetOutputter(
-        Writer writer, BiPredicate<Rule, Attribute> preserveSelect, String lineTerm) {
+        Writer writer,
+        BiPredicate<Rule, Attribute> preserveSelect,
+        String lineTerm,
+        LabelPrinter labelPrinter) {
       this.writer = writer;
       this.preserveSelect = preserveSelect;
       this.lineTerm = lineTerm;
+      this.labelPrinter = labelPrinter;
     }
 
     /** Outputs a given target in BUILD-style syntax. */
@@ -193,7 +198,7 @@
         // Print labels in their canonical form.
         @Override
         public Printer repr(Object o) {
-          return super.repr(o instanceof Label ? ((Label) o).getCanonicalForm() : o);
+          return super.repr(o instanceof Label ? labelPrinter.toString((Label) o) : o);
         }
       }.repr(value).toString();
     }
@@ -222,28 +227,29 @@
   /** Query's implementation. */
   @Override
   public OutputFormatterCallback<Target> createPostFactoStreamCallback(
-      OutputStream out, final QueryOptions options, RepositoryMapping mainRepoMapping) {
-    return new BuildOutputFormatterCallback(out, options.getLineTerminator());
+      OutputStream out, final QueryOptions options, LabelPrinter labelPrinter) {
+    return new BuildOutputFormatterCallback(out, options.getLineTerminator(), labelPrinter);
   }
 
   @Override
   public ThreadSafeOutputFormatterCallback<Target> createStreamCallback(
       OutputStream out, QueryOptions options, QueryEnvironment<?> env) {
     return new SynchronizedDelegatingOutputFormatterCallback<>(
-        createPostFactoStreamCallback(out, options, env.getMainRepoMapping()));
+        createPostFactoStreamCallback(out, options, env.getLabelPrinter()));
   }
 
   /** BuildOutputFormatter callback for Query. Made visible for ModQuery. */
   public static class BuildOutputFormatterCallback extends TextOutputFormatterCallback<Target> {
     private final TargetOutputter targetOutputter;
 
-    BuildOutputFormatterCallback(OutputStream out, String lineTerm) {
+    BuildOutputFormatterCallback(OutputStream out, String lineTerm, LabelPrinter labelPrinter) {
       super(out);
       this.targetOutputter =
           new TargetOutputter(
               writer,
               (rule, attr) -> RawAttributeMapper.of(rule).isConfigurable(attr.getName()),
-              lineTerm);
+              lineTerm,
+              labelPrinter);
     }
 
     @Override
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/GraphOutputFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/GraphOutputFormatter.java
index f92ddf8..86725ed 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/GraphOutputFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/GraphOutputFormatter.java
@@ -14,10 +14,10 @@
 package com.google.devtools.build.lib.query2.query.output;
 
 import com.google.common.hash.HashFunction;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.graph.Digraph;
 import com.google.devtools.build.lib.graph.Node;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.query2.query.aspectresolvers.AspectResolver;
 import com.google.devtools.build.lib.query2.query.output.FormatUtils.TargetOrdering;
@@ -41,9 +41,9 @@
         private final TargetOrdering targetOrdering = new FormatUtils.TargetOrdering();
 
         @Override
-        public String getLabel(Node<Target> node, RepositoryMapping mainRepositoryMapping) {
+        public String getLabel(Node<Target> node, LabelPrinter labelPrinter) {
           // Node payloads are Targets. Output node labels are target labels.
-          return node.getLabel().getLabel().getDisplayForm(mainRepositoryMapping);
+          return labelPrinter.toString(node.getLabel().getLabel());
         }
 
         @Override
@@ -60,7 +60,7 @@
       AspectResolver aspectProvider,
       EventHandler eventHandler,
       HashFunction hashFunction,
-      RepositoryMapping mainRepoMapping) {
+      LabelPrinter labelPrinter) {
     boolean sortLabels = options.orderOutput == OrderOutput.FULL;
     GraphOutputWriter<Target> graphWriter =
         new GraphOutputWriter<>(
@@ -70,7 +70,7 @@
             options.graphNodeStringLimit,
             options.graphConditionalEdgesLimit,
             options.graphFactored,
-            mainRepoMapping);
+            labelPrinter);
     graphWriter.write(result, new ConditionalEdges(result), out);
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/GraphOutputWriter.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/GraphOutputWriter.java
index f803362..bdf4d32 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/GraphOutputWriter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/GraphOutputWriter.java
@@ -19,13 +19,13 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Ordering;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.collect.CollectionUtils;
 import com.google.devtools.build.lib.collect.EquivalenceRelation;
 import com.google.devtools.build.lib.graph.Digraph;
 import com.google.devtools.build.lib.graph.DotOutputVisitor;
 import com.google.devtools.build.lib.graph.LabelSerializer;
 import com.google.devtools.build.lib.graph.Node;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
@@ -55,7 +55,7 @@
      * <p>This is not the same as a build {@link Label}. This is just the text associated with a
      * node in a GraphViz graph.
      */
-    String getLabel(Node<T> node, RepositoryMapping mainRepositoryMapping);
+    String getLabel(Node<T> node, LabelPrinter labelPrinter);
 
     /** Returns a comparator for the build graph nodes that form the payloads of GraphViz nodes. */
     Comparator<T> comparator();
@@ -68,7 +68,7 @@
   private final int maxConditionalEdges;
   private final boolean mergeEquivalentNodes;
   private final Ordering<Node<T>> nodeComparator;
-  private final RepositoryMapping mainRepoMapping;
+  private final LabelPrinter labelPrinter;
 
   private static final int RESERVED_LABEL_CHARS = "\\n...and 9999999 more items".length();
 
@@ -93,14 +93,14 @@
       int maxLabelSize,
       int maxConditionalEdges,
       boolean mergeEquivalentNodes,
-      RepositoryMapping mainRepoMapping) {
+      LabelPrinter labelPrinter) {
     this.nodeReader = nodeReader;
     this.lineTerminator = lineTerminator;
     this.sortLabels = sortLabels;
     this.maxLabelSize = maxLabelSize;
     this.maxConditionalEdges = maxConditionalEdges;
     this.mergeEquivalentNodes = mergeEquivalentNodes;
-    this.mainRepoMapping = mainRepoMapping;
+    this.labelPrinter = labelPrinter;
     nodeComparator = Ordering.from(nodeReader.comparator()).onResultOf(Node::getLabel);
   }
 
@@ -124,7 +124,7 @@
   private void outputUnfactored(
       Digraph<T> graph, @Nullable ConditionalEdges conditionalEdges, PrintWriter out) {
     graph.visitNodesBeforeEdges(
-        new DotOutputVisitor<T>(out, node -> nodeReader.getLabel(node, mainRepoMapping)) {
+        new DotOutputVisitor<T>(out, node -> nodeReader.getLabel(node, labelPrinter)) {
           @Override
           public void beginVisit() {
             super.beginVisit();
@@ -184,7 +184,7 @@
           StringBuilder buf = new StringBuilder();
           int count = 0;
           for (Node<T> eqNode : node.getLabel()) {
-            String labelString = nodeReader.getLabel(eqNode, mainRepoMapping);
+            String labelString = nodeReader.getLabel(eqNode, labelPrinter);
             if (!firstItem) {
               buf.append("\\n");
 
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/LabelOutputFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/LabelOutputFormatter.java
index 6826106..7e7c667 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/LabelOutputFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/LabelOutputFormatter.java
@@ -15,7 +15,7 @@
 package com.google.devtools.build.lib.query2.query.output;
 
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.query2.engine.OutputFormatterCallback;
 import com.google.devtools.build.lib.query2.engine.QueryEnvironment;
@@ -43,7 +43,7 @@
 
   @Override
   public OutputFormatterCallback<Target> createPostFactoStreamCallback(
-      OutputStream out, final QueryOptions options, RepositoryMapping mainRepoMapping) {
+      OutputStream out, final QueryOptions options, LabelPrinter labelPrinter) {
     return new TextOutputFormatterCallback<Target>(out) {
       @Override
       public void processOutput(Iterable<Target> partialResult) throws IOException {
@@ -54,7 +54,7 @@
             writer.append(' ');
           }
           Label label = target.getLabel();
-          writer.append(label.getDisplayForm(mainRepoMapping)).append(lineTerm);
+          writer.append(labelPrinter.toString(label)).append(lineTerm);
         }
       }
     };
@@ -64,6 +64,6 @@
   public ThreadSafeOutputFormatterCallback<Target> createStreamCallback(
       OutputStream out, QueryOptions options, QueryEnvironment<?> env) {
     return new SynchronizedDelegatingOutputFormatterCallback<>(
-        createPostFactoStreamCallback(out, options, env.getMainRepoMapping()));
+        createPostFactoStreamCallback(out, options, env.getLabelPrinter()));
   }
 }
\ No newline at end of file
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/LocationOutputFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/LocationOutputFormatter.java
index 6d2af48..00edf48 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/LocationOutputFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/LocationOutputFormatter.java
@@ -16,7 +16,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.hash.HashFunction;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.query2.common.AbstractBlazeQueryEnvironment;
 import com.google.devtools.build.lib.query2.common.CommonQueryOptions;
@@ -76,7 +76,7 @@
 
   @Override
   public OutputFormatterCallback<Target> createPostFactoStreamCallback(
-      OutputStream out, final QueryOptions options, RepositoryMapping mainRepoMapping) {
+      OutputStream out, final QueryOptions options, LabelPrinter labelPrinter) {
     return new TextOutputFormatterCallback<Target>(out) {
 
       @Override
@@ -88,7 +88,7 @@
               .append(": ")
               .append(target.getTargetKind())
               .append(" ")
-              .append(target.getLabel().getDisplayForm(mainRepoMapping))
+              .append(labelPrinter.toString(target.getLabel()))
               .append(lineTerm);
         }
       }
@@ -99,6 +99,6 @@
   public ThreadSafeOutputFormatterCallback<Target> createStreamCallback(
       OutputStream out, QueryOptions options, QueryEnvironment<?> env) {
     return new SynchronizedDelegatingOutputFormatterCallback<>(
-        createPostFactoStreamCallback(out, options, env.getMainRepoMapping()));
+        createPostFactoStreamCallback(out, options, env.getLabelPrinter()));
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/MaxrankOutputFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/MaxrankOutputFormatter.java
index 0cfc33e..6599713 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/MaxrankOutputFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/MaxrankOutputFormatter.java
@@ -17,10 +17,10 @@
 import static java.util.Comparator.comparingInt;
 
 import com.google.common.hash.HashFunction;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.graph.Digraph;
 import com.google.devtools.build.lib.graph.Node;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.query2.query.aspectresolvers.AspectResolver;
 import com.google.devtools.build.lib.query2.query.output.QueryOptions.OrderOutput;
@@ -60,7 +60,7 @@
       AspectResolver aspectResolver,
       EventHandler eventHandler,
       HashFunction hashFunction,
-      RepositoryMapping mainRepoMapping)
+      LabelPrinter labelPrinter)
       throws IOException {
     // In order to handle cycles correctly, we need work on the strong
     // component graph, as cycles should be treated a "clump" of nodes all on
@@ -104,7 +104,7 @@
     final String lineTerm = options.getLineTerminator();
     PrintStream printStream = new PrintStream(out);
     for (RankAndLabel item : output) {
-      printStream.print(item.toDisplayString(mainRepoMapping) + lineTerm);
+      printStream.print(item.toString(labelPrinter) + lineTerm);
     }
     flushAndCheckError(printStream);
   }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/MinrankOutputFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/MinrankOutputFormatter.java
index b4236a8..638b515 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/MinrankOutputFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/MinrankOutputFormatter.java
@@ -16,10 +16,10 @@
 
 import com.google.common.hash.HashFunction;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.graph.Digraph;
 import com.google.devtools.build.lib.graph.Node;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.query2.query.aspectresolvers.AspectResolver;
 import com.google.devtools.build.lib.query2.query.output.QueryOptions.OrderOutput;
@@ -56,11 +56,12 @@
       Label label,
       PrintStream out,
       @Nullable List<RankAndLabel> toSave,
-      final String lineTerminator) {
+      final String lineTerminator,
+      LabelPrinter labelPrinter) {
     if (toSave != null) {
       toSave.add(new RankAndLabel(rank, label));
     } else {
-      out.print(rank + " " + label.getCanonicalForm() + lineTerminator);
+      out.print(rank + " " + labelPrinter.toString(label) + lineTerminator);
     }
   }
 
@@ -72,7 +73,7 @@
       AspectResolver aspectResolver,
       EventHandler eventHandler,
       HashFunction hashFunction,
-      RepositoryMapping mainRepoMapping)
+      LabelPrinter labelPrinter)
       throws IOException {
     PrintStream printStream = new PrintStream(out);
     // getRoots() isn't defined for cyclic graphs, so in order to handle
@@ -92,7 +93,7 @@
       for (Node<Set<Node<Target>>> xScc : rankNodes) {
         for (Node<Target> x : xScc.getLabel()) {
           outputToStreamOrSave(
-              rank, x.getLabel().getLabel(), printStream, outputToOrder, lineTerm);
+              rank, x.getLabel().getLabel(), printStream, outputToOrder, lineTerm, labelPrinter);
         }
       }
 
@@ -110,7 +111,7 @@
     if (outputToOrder != null) {
       Collections.sort(outputToOrder);
       for (RankAndLabel item : outputToOrder) {
-        printStream.print(item.toDisplayString(mainRepoMapping) + lineTerm);
+        printStream.print(item.toString(labelPrinter) + lineTerm);
       }
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/OutputFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/OutputFormatter.java
index 5b33485..20b0367 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/OutputFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/OutputFormatter.java
@@ -14,9 +14,9 @@
 package com.google.devtools.build.lib.query2.query.output;
 
 import com.google.common.hash.HashFunction;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.graph.Digraph;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.query2.engine.QueryEnvironment;
 import com.google.devtools.build.lib.query2.engine.QueryException;
@@ -60,6 +60,6 @@
       AspectResolver aspectProvider,
       @Nullable EventHandler eventHandler,
       HashFunction hashFunction,
-      RepositoryMapping mainRepoMapping)
+      LabelPrinter labelPrinter)
       throws IOException, InterruptedException;
 }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/PackageOutputFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/PackageOutputFormatter.java
index 70751a8..989cad1 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/PackageOutputFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/PackageOutputFormatter.java
@@ -15,7 +15,7 @@
 package com.google.devtools.build.lib.query2.query.output;
 
 import com.google.common.collect.Sets;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.query2.engine.OutputFormatterCallback;
 import com.google.devtools.build.lib.query2.engine.QueryEnvironment;
@@ -38,7 +38,7 @@
 
   @Override
   public OutputFormatterCallback<Target> createPostFactoStreamCallback(
-      OutputStream out, final QueryOptions options, RepositoryMapping mainRepoMapping) {
+      OutputStream out, final QueryOptions options, LabelPrinter labelPrinter) {
     return new TextOutputFormatterCallback<Target>(out) {
       private final Set<String> packageNames = Sets.newTreeSet();
 
@@ -46,8 +46,7 @@
       public void processOutput(Iterable<Target> partialResult) {
 
         for (Target target : partialResult) {
-          String packageLabel =
-              target.getLabel().getPackageIdentifier().getDisplayForm(mainRepoMapping);
+          String packageLabel = labelPrinter.toString(target.getLabel().getPackageIdentifier());
           // For backwards compatibility, emit main repo packages as "a/b" rather than "//a/b".
           if (packageLabel.startsWith("//")) {
             packageLabel = packageLabel.substring(2);
@@ -73,6 +72,6 @@
   public ThreadSafeOutputFormatterCallback<Target> createStreamCallback(
       OutputStream out, QueryOptions options, QueryEnvironment<?> env) {
     return new SynchronizedDelegatingOutputFormatterCallback<>(
-        createPostFactoStreamCallback(out, options, env.getMainRepoMapping()));
+        createPostFactoStreamCallback(out, options, env.getLabelPrinter()));
   }
 }
\ No newline at end of file
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/ProtoOutputFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/ProtoOutputFormatter.java
index 5239e1c..a467a41 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/ProtoOutputFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/ProtoOutputFormatter.java
@@ -31,7 +31,6 @@
 import com.google.common.hash.HashFunction;
 import com.google.common.io.BaseEncoding;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.packages.AggregatingAttributeMapper;
@@ -41,6 +40,7 @@
 import com.google.devtools.build.lib.packages.DependencyFilter;
 import com.google.devtools.build.lib.packages.EnvironmentGroup;
 import com.google.devtools.build.lib.packages.InputFile;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.OutputFile;
 import com.google.devtools.build.lib.packages.PackageGroup;
 import com.google.devtools.build.lib.packages.ProtoUtils;
@@ -155,24 +155,26 @@
 
   @Override
   public OutputFormatterCallback<Target> createPostFactoStreamCallback(
-      OutputStream out, QueryOptions options, RepositoryMapping mainRepoMapping) {
-    return new StreamedQueryResultFormatter(out);
+      OutputStream out, QueryOptions options, LabelPrinter labelPrinter) {
+    return new StreamedQueryResultFormatter(out, labelPrinter);
   }
 
   @Override
   public ThreadSafeOutputFormatterCallback<Target> createStreamCallback(
       OutputStream out, QueryOptions options, QueryEnvironment<?> env) {
     return new SynchronizedDelegatingOutputFormatterCallback<>(
-        createPostFactoStreamCallback(out, options, env.getMainRepoMapping()));
+        createPostFactoStreamCallback(out, options, env.getLabelPrinter()));
   }
 
   /** Converts a logical {@link Target} object into a {@link Build.Target} protobuffer. */
-  public Build.Target toTargetProtoBuffer(Target target) throws InterruptedException {
-    return toTargetProtoBuffer(target, /*extraDataForAttrHash=*/ "");
+  public Build.Target toTargetProtoBuffer(Target target, LabelPrinter labelPrinter)
+      throws InterruptedException {
+    return toTargetProtoBuffer(target, labelPrinter, /* extraDataForAttrHash= */ "");
   }
 
   /** Converts a logical {@link Target} object into a {@link Build.Target} protobuffer. */
-  public Build.Target toTargetProtoBuffer(Target target, Object extraDataForAttrHash)
+  public Build.Target toTargetProtoBuffer(
+      Target target, LabelPrinter labelPrinter, Object extraDataForAttrHash)
       throws InterruptedException {
     Build.Target.Builder targetPb = Build.Target.newBuilder();
 
@@ -180,12 +182,12 @@
       Rule rule = (Rule) target;
       Build.Rule.Builder rulePb =
           Build.Rule.newBuilder()
-              .setName(rule.getLabel().toString())
+              .setName(labelPrinter.toString(rule.getLabel()))
               .setRuleClass(rule.getRuleClass());
       if (includeLocations) {
         rulePb.setLocation(FormatUtils.getLocation(target, relativeLocations));
       }
-      addAttributes(rulePb, rule, extraDataForAttrHash);
+      addAttributes(rulePb, rule, extraDataForAttrHash, labelPrinter);
       byte[] transitiveDigest = rule.getRuleClassObject().getRuleDefinitionEnvironmentDigest();
       if (transitiveDigest != null && includeRuleDefinitionEnvironment()) {
         // The RuleDefinitionEnvironment is always defined for Starlark rules and
@@ -216,7 +218,8 @@
                   attribute,
                   attributeValue,
                   /*explicitlySpecified=*/ false,
-                  /*encodeBooleanAndTriStateAsIntegerAndString=*/ true);
+                  /*encodeBooleanAndTriStateAsIntegerAndString=*/ true,
+                  labelPrinter);
           attributes.add(serializedAttribute);
         }
         rulePb.addAllAttribute(
@@ -227,16 +230,16 @@
         if (!aspectsDependencies.isEmpty()) {
           aspectsDependencies.values().stream()
               .distinct()
-              .forEach(dep -> rulePb.addRuleInput(dep.toString()));
+              .forEach(dep -> rulePb.addRuleInput(labelPrinter.toString(dep)));
         }
         // Include explicit elements for all direct inputs and outputs of a rule; this goes beyond
         // what is available from the attributes above, since it may also (depending on options)
         // include implicit outputs, host-configuration outputs, and default values.
         rule.getSortedLabels(dependencyFilter)
-            .forEach(input -> rulePb.addRuleInput(input.toString()));
+            .forEach(input -> rulePb.addRuleInput(labelPrinter.toString(input)));
         rule.getOutputFiles().stream()
             .distinct()
-            .forEach(output -> rulePb.addRuleOutput(output.getLabel().toString()));
+            .forEach(output -> rulePb.addRuleOutput(labelPrinter.toString(output.getLabel())));
       }
       for (String feature : rule.getPackage().getFeatures()) {
         rulePb.addDefaultSetting(feature);
@@ -268,8 +271,8 @@
       Rule generatingRule = outputFile.getGeneratingRule();
       GeneratedFile.Builder output =
           GeneratedFile.newBuilder()
-              .setGeneratingRule(generatingRule.getLabel().toString())
-              .setName(label.toString());
+              .setGeneratingRule(labelPrinter.toString(generatingRule.getLabel()))
+              .setName(labelPrinter.toString(label));
 
       if (includeLocations) {
         output.setLocation(FormatUtils.getLocation(target, relativeLocations));
@@ -280,7 +283,8 @@
       InputFile inputFile = (InputFile) target;
       Label label = inputFile.getLabel();
 
-      Build.SourceFile.Builder input = Build.SourceFile.newBuilder().setName(label.toString());
+      Build.SourceFile.Builder input =
+          Build.SourceFile.newBuilder().setName(labelPrinter.toString(label));
 
       if (includeLocations) {
         input.setLocation(
@@ -294,7 +298,7 @@
                 : aspectResolver.computeBuildFileDependencies(inputFile.getPackage());
 
         for (Label starlarkLoadLabel : starlarkLoadLabels) {
-          input.addSubinclude(starlarkLoadLabel.toString());
+          input.addSubinclude(labelPrinter.toString(starlarkLoadLabel));
         }
 
         for (String feature : inputFile.getPackage().getFeatures()) {
@@ -305,18 +309,18 @@
       }
 
       for (Label visibilityDependency : target.getVisibility().getDependencyLabels()) {
-        input.addPackageGroup(visibilityDependency.toString());
+        input.addPackageGroup(labelPrinter.toString(visibilityDependency));
       }
 
       for (Label visibilityDeclaration : target.getVisibility().getDeclaredLabels()) {
-        input.addVisibilityLabel(visibilityDeclaration.toString());
+        input.addVisibilityLabel(labelPrinter.toString(visibilityDeclaration));
       }
 
       targetPb.setType(SOURCE_FILE);
       targetPb.setSourceFile(input);
     } else if (target instanceof FakeLoadTarget) {
       Label label = target.getLabel();
-      SourceFile.Builder input = SourceFile.newBuilder().setName(label.toString());
+      SourceFile.Builder input = SourceFile.newBuilder().setName(labelPrinter.toString(label));
 
       if (includeLocations) {
         input.setLocation(FormatUtils.getLocation(target, relativeLocations));
@@ -326,13 +330,13 @@
     } else if (target instanceof PackageGroup) {
       PackageGroup packageGroup = (PackageGroup) target;
       Build.PackageGroup.Builder packageGroupPb =
-          Build.PackageGroup.newBuilder().setName(packageGroup.getLabel().toString());
+          Build.PackageGroup.newBuilder().setName(labelPrinter.toString(packageGroup.getLabel()));
       for (String containedPackage :
           packageGroup.getContainedPackages(packageGroupIncludesDoubleSlash)) {
         packageGroupPb.addContainedPackage(containedPackage);
       }
       for (Label include : packageGroup.getIncludes()) {
-        packageGroupPb.addIncludedPackageGroup(include.toString());
+        packageGroupPb.addIncludedPackageGroup(labelPrinter.toString(include));
       }
 
       targetPb.setType(PACKAGE_GROUP);
@@ -340,12 +344,12 @@
     } else if (target instanceof EnvironmentGroup) {
       EnvironmentGroup envGroup = (EnvironmentGroup) target;
       Build.EnvironmentGroup.Builder envGroupPb =
-          Build.EnvironmentGroup.newBuilder().setName(envGroup.getLabel().toString());
+          Build.EnvironmentGroup.newBuilder().setName(labelPrinter.toString(envGroup.getLabel()));
       for (Label env : envGroup.getEnvironments()) {
-        envGroupPb.addEnvironment(env.toString());
+        envGroupPb.addEnvironment(labelPrinter.toString(env));
       }
       for (Label defaultEnv : envGroup.getDefaults()) {
-        envGroupPb.addDefault(defaultEnv.toString());
+        envGroupPb.addDefault(labelPrinter.toString(defaultEnv));
       }
       targetPb.setType(ENVIRONMENT_GROUP);
       targetPb.setEnvironmentGroup(envGroupPb);
@@ -356,7 +360,11 @@
     return targetPb.build();
   }
 
-  protected void addAttributes(Build.Rule.Builder rulePb, Rule rule, Object extraDataForAttrHash) {
+  protected void addAttributes(
+      Build.Rule.Builder rulePb,
+      Rule rule,
+      Object extraDataForAttrHash,
+      LabelPrinter labelPrinter) {
     Map<Attribute, Build.Attribute> serializedAttributes = Maps.newHashMap();
     AggregatingAttributeMapper attributeMapper = AggregatingAttributeMapper.of(rule);
     for (Attribute attr : rule.getAttributes()) {
@@ -374,7 +382,8 @@
               attr,
               attributeValue,
               rule.isAttributeValueExplicitlySpecified(attr),
-              /*encodeBooleanAndTriStateAsIntegerAndString=*/ true);
+              /* encodeBooleanAndTriStateAsIntegerAndString= */ true,
+              labelPrinter);
       serializedAttributes.put(attr, serializedAttribute);
     }
     rulePb.addAllAttribute(
@@ -535,9 +544,11 @@
     private static final int OUTPUT_BUFFER_SIZE = 16384;
 
     private final CodedOutputStream codedOut;
+    private final LabelPrinter labelPrinter;
 
-    private StreamedQueryResultFormatter(OutputStream out) {
+    private StreamedQueryResultFormatter(OutputStream out, LabelPrinter labelPrinter) {
       this.codedOut = CodedOutputStream.newInstance(out, OUTPUT_BUFFER_SIZE);
+      this.labelPrinter = labelPrinter;
     }
 
     @Override
@@ -548,7 +559,8 @@
       // constructing and serializing a QueryResult proto are protected by test coverage and proto
       // best practices.
       for (Target target : partialResult) {
-        codedOut.writeMessage(QueryResult.TARGET_FIELD_NUMBER, toTargetProtoBuffer(target));
+        codedOut.writeMessage(
+            QueryResult.TARGET_FIELD_NUMBER, toTargetProtoBuffer(target, labelPrinter));
       }
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/QueryOutputUtils.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/QueryOutputUtils.java
index fc35465..03602eb 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/QueryOutputUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/QueryOutputUtils.java
@@ -14,9 +14,9 @@
 package com.google.devtools.build.lib.query2.query.output;
 
 import com.google.common.hash.HashFunction;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.graph.Digraph;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.profiler.Profiler;
 import com.google.devtools.build.lib.profiler.SilentCloseable;
@@ -61,7 +61,7 @@
       AspectResolver aspectResolver,
       @Nullable EventHandler eventHandler,
       HashFunction hashFunction,
-      RepositoryMapping mainRepoMapping)
+      LabelPrinter labelPrinter)
       throws IOException, InterruptedException {
     /*
      * This is not really streaming, but we are using the streaming interface for writing into the
@@ -73,8 +73,7 @@
       streamedFormatter.setOptions(queryOptions, aspectResolver, hashFunction);
       streamedFormatter.setEventHandler(eventHandler);
       OutputFormatterCallback.processAllTargets(
-          streamedFormatter.createPostFactoStreamCallback(
-              outputStream, queryOptions, mainRepoMapping),
+          streamedFormatter.createPostFactoStreamCallback(outputStream, queryOptions, labelPrinter),
           targetsResult);
     } else {
       @SuppressWarnings("unchecked")
@@ -94,7 +93,7 @@
             aspectResolver,
             eventHandler,
             hashFunction,
-            mainRepoMapping);
+            labelPrinter);
       }
     }
   }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/RankAndLabel.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/RankAndLabel.java
index 3b95782..4782925 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/RankAndLabel.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/RankAndLabel.java
@@ -15,7 +15,7 @@
 package com.google.devtools.build.lib.query2.query.output;
 
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 
 class RankAndLabel implements Comparable<RankAndLabel> {
   private final int rank;
@@ -40,10 +40,10 @@
 
   @Override
   public String toString() {
-    return toDisplayString(RepositoryMapping.ALWAYS_FALLBACK);
+    throw new UnsupportedOperationException("Use toString(LabelPrinter) instead");
   }
 
-  public String toDisplayString(RepositoryMapping mainRepoMapping) {
-    return rank + " " + label.getDisplayForm(mainRepoMapping);
+  public String toString(LabelPrinter labelPrinter) {
+    return rank + " " + labelPrinter.toString(label);
   }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/StreamedFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/StreamedFormatter.java
index 789c2c6..d3234a6 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/StreamedFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/StreamedFormatter.java
@@ -15,8 +15,8 @@
 package com.google.devtools.build.lib.query2.query.output;
 
 import com.google.common.hash.HashFunction;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.query2.common.CommonQueryOptions;
 import com.google.devtools.build.lib.query2.engine.OutputFormatterCallback;
@@ -63,5 +63,5 @@
    * already-computed result of a query.
    */
   OutputFormatterCallback<Target> createPostFactoStreamCallback(
-      OutputStream out, QueryOptions options, RepositoryMapping mainRepoMapping);
+      OutputStream out, QueryOptions options, LabelPrinter labelPrinter);
 }
\ No newline at end of file
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/StreamedJSONProtoOutputFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/StreamedJSONProtoOutputFormatter.java
index d8509de..541b006 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/StreamedJSONProtoOutputFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/StreamedJSONProtoOutputFormatter.java
@@ -13,7 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.query2.query.output;
 
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.query2.engine.OutputFormatterCallback;
 import com.google.protobuf.util.JsonFormat;
@@ -35,7 +35,7 @@
 
   @Override
   public OutputFormatterCallback<Target> createPostFactoStreamCallback(
-      final OutputStream out, final QueryOptions options, RepositoryMapping mainRepoMapping) {
+      final OutputStream out, final QueryOptions options, LabelPrinter labelPrinter) {
     return new OutputFormatterCallback<Target>() {
       @Override
       public void processOutput(Iterable<Target> partialResult)
@@ -44,7 +44,7 @@
           out.write(
               jsonPrinter
                   .omittingInsignificantWhitespace()
-                  .print(toTargetProtoBuffer(target))
+                  .print(toTargetProtoBuffer(target, labelPrinter))
                   .getBytes(StandardCharsets.UTF_8));
           out.write(System.lineSeparator().getBytes(StandardCharsets.UTF_8));
         }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/StreamedProtoOutputFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/StreamedProtoOutputFormatter.java
index 4adb1a8..51c1c3e 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/StreamedProtoOutputFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/StreamedProtoOutputFormatter.java
@@ -13,7 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.query2.query.output;
 
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.query2.engine.OutputFormatterCallback;
 import java.io.IOException;
@@ -32,13 +32,13 @@
 
   @Override
   public OutputFormatterCallback<Target> createPostFactoStreamCallback(
-      final OutputStream out, final QueryOptions options, RepositoryMapping mainRepoMapping) {
+      final OutputStream out, final QueryOptions options, LabelPrinter labelPrinter) {
     return new OutputFormatterCallback<Target>() {
       @Override
       public void processOutput(Iterable<Target> partialResult)
           throws IOException, InterruptedException {
         for (Target target : partialResult) {
-          toTargetProtoBuffer(target).writeDelimitedTo(out);
+          toTargetProtoBuffer(target, labelPrinter).writeDelimitedTo(out);
         }
       }
     };
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/SyntheticAttributeHashCalculator.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/SyntheticAttributeHashCalculator.java
index 1b1769a..4b4b11c 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/SyntheticAttributeHashCalculator.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/SyntheticAttributeHashCalculator.java
@@ -24,6 +24,7 @@
 import com.google.devtools.build.lib.packages.Attribute.ComputedDefault;
 import com.google.devtools.build.lib.packages.AttributeFormatter;
 import com.google.devtools.build.lib.packages.BuildType.SelectorList;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.RawAttributeMapper;
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -118,7 +119,8 @@
                 attr,
                 valueToHash,
                 /* explicitlySpecified= */ false, // We care about value, not how it was set.
-                /*encodeBooleanAndTriStateAsIntegerAndString=*/ false);
+                /* encodeBooleanAndTriStateAsIntegerAndString= */ false,
+                LabelPrinter.legacy());
       } else {
         attrPb = serializedAttributes.get(attr);
       }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/XmlOutputFormatter.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/XmlOutputFormatter.java
index 9690836..d2af9b5 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/XmlOutputFormatter.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/XmlOutputFormatter.java
@@ -18,12 +18,12 @@
 import com.google.common.collect.Iterables;
 import com.google.common.hash.HashFunction;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.BuildType;
 import com.google.devtools.build.lib.packages.DependencyFilter;
 import com.google.devtools.build.lib.packages.EnvironmentGroup;
 import com.google.devtools.build.lib.packages.InputFile;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.License;
 import com.google.devtools.build.lib.packages.OutputFile;
 import com.google.devtools.build.lib.packages.PackageGroup;
@@ -76,7 +76,7 @@
   public ThreadSafeOutputFormatterCallback<Target> createStreamCallback(
       OutputStream out, QueryOptions options, QueryEnvironment<?> env) {
     return new SynchronizedDelegatingOutputFormatterCallback<>(
-        createPostFactoStreamCallback(out, options, env.getMainRepoMapping()));
+        createPostFactoStreamCallback(out, options, env.getLabelPrinter()));
   }
 
   @Override
@@ -95,7 +95,7 @@
 
   @Override
   public OutputFormatterCallback<Target> createPostFactoStreamCallback(
-      OutputStream out, QueryOptions options, RepositoryMapping mainRepoMapping) {
+      OutputStream out, QueryOptions options, LabelPrinter labelPrinter) {
     return new OutputFormatterCallback<Target>() {
 
       private Document doc;
@@ -119,7 +119,7 @@
       @Override
       public void processOutput(Iterable<Target> partialResult) throws InterruptedException {
         for (Target target : partialResult) {
-          queryElem.appendChild(createTargetElement(doc, target));
+          queryElem.appendChild(createTargetElement(doc, target, labelPrinter));
         }
       }
 
@@ -142,15 +142,12 @@
   /**
    * Creates and returns a new DOM tree for the specified build target.
    *
-   * XML structure:
-   * - element tag is &lt;source-file>, &lt;generated-file> or &lt;rule
-   *   class="cc_library">, following the terminology of
-   *   {@link Target#getTargetKind()}.
-   * - 'name' attribute is target's label.
-   * - 'location' attribute is consistent with output of --output location.
-   * - rule attributes are represented in the DOM structure.
+   * <p>XML structure: - element tag is &lt;source-file>, &lt;generated-file> or &lt;rule
+   * class="cc_library">, following the terminology of {@link Target#getTargetKind()}. - 'name'
+   * attribute is target's label. - 'location' attribute is consistent with output of --output
+   * location. - rule attributes are represented in the DOM structure.
    */
-  private Element createTargetElement(Document doc, Target target)
+  private Element createTargetElement(Document doc, Target target, LabelPrinter labelPrinter)
       throws InterruptedException {
     Element elem;
     if (target instanceof Rule) {
@@ -166,8 +163,8 @@
           //  values.
           Iterable<Object> values =
               PossibleAttributeValues.forRuleAndAttribute(
-                  rule, attr, /*mayTreatMultipleAsNone=*/ false);
-          Element attrElem = createValueElement(doc, attr.getType(), values);
+                  rule, attr, /* mayTreatMultipleAsNone= */ false);
+          Element attrElem = createValueElement(doc, attr.getType(), values, labelPrinter);
           attrElem.setAttribute("name", attr.getName());
           elem.appendChild(attrElem);
         }
@@ -179,18 +176,18 @@
       // host-configuration outputs, and default values.
       for (Label label : rule.getSortedLabels(dependencyFilter)) {
         Element inputElem = doc.createElement("rule-input");
-        inputElem.setAttribute("name", label.toString());
+        inputElem.setAttribute("name", labelPrinter.toString(label));
         elem.appendChild(inputElem);
       }
       for (Label label :
           aspectResolver.computeAspectDependencies(target, dependencyFilter).values()) {
         Element inputElem = doc.createElement("rule-input");
-        inputElem.setAttribute("name", label.toString());
+        inputElem.setAttribute("name", labelPrinter.toString(label));
         elem.appendChild(inputElem);
       }
       for (OutputFile outputFile : rule.getOutputFiles()) {
         Element outputElem = doc.createElement("rule-output");
-        outputElem.setAttribute("name", outputFile.getLabel().toString());
+        outputElem.setAttribute("name", labelPrinter.toString(outputFile.getLabel()));
         elem.appendChild(outputElem);
       }
       for (String feature : rule.getPackage().getFeatures()) {
@@ -202,46 +199,44 @@
       PackageGroup packageGroup = (PackageGroup) target;
       elem = doc.createElement("package-group");
       elem.setAttribute("name", packageGroup.getName());
-      Element includes = createValueElement(doc,
-          BuildType.LABEL_LIST,
-          packageGroup.getIncludes());
+      Element includes =
+          createValueElement(doc, BuildType.LABEL_LIST, packageGroup.getIncludes(), labelPrinter);
       includes.setAttribute("name", "includes");
       elem.appendChild(includes);
       Element packages =
           createValueElement(
               doc,
               Type.STRING_LIST,
-              packageGroup.getContainedPackages(packageGroupIncludesDoubleSlash));
+              packageGroup.getContainedPackages(packageGroupIncludesDoubleSlash),
+              labelPrinter);
       packages.setAttribute("name", "packages");
       elem.appendChild(packages);
     } else if (target instanceof OutputFile) {
       OutputFile outputFile = (OutputFile) target;
       elem = doc.createElement("generated-file");
-      elem.setAttribute("generating-rule",
-                        outputFile.getGeneratingRule().getLabel().toString());
+      elem.setAttribute(
+          "generating-rule", labelPrinter.toString(outputFile.getGeneratingRule().getLabel()));
     } else if (target instanceof InputFile) {
       elem = doc.createElement("source-file");
       InputFile inputFile = (InputFile) target;
       if (inputFile.getName().equals("BUILD")) {
-        addStarlarkFilesToElement(doc, elem, inputFile);
+        addStarlarkFilesToElement(doc, elem, inputFile, labelPrinter);
         addFeaturesToElement(doc, elem, inputFile);
         elem.setAttribute("package_contains_errors",
             String.valueOf(inputFile.getPackage().containsErrors()));
       }
 
-      addPackageGroupsToElement(doc, elem, inputFile);
+      addPackageGroupsToElement(doc, elem, inputFile, labelPrinter);
     } else if (target instanceof EnvironmentGroup) {
       EnvironmentGroup envGroup = (EnvironmentGroup) target;
       elem = doc.createElement("environment-group");
       elem.setAttribute("name", envGroup.getName());
-      Element environments = createValueElement(doc,
-          BuildType.LABEL_LIST,
-          envGroup.getEnvironments());
+      Element environments =
+          createValueElement(doc, BuildType.LABEL_LIST, envGroup.getEnvironments(), labelPrinter);
       environments.setAttribute("name", "environments");
       elem.appendChild(environments);
-      Element defaults = createValueElement(doc,
-          BuildType.LABEL_LIST,
-          envGroup.getDefaults());
+      Element defaults =
+          createValueElement(doc, BuildType.LABEL_LIST, envGroup.getDefaults(), labelPrinter);
       defaults.setAttribute("name", "defaults");
       elem.appendChild(defaults);
     } else if (target instanceof FakeLoadTarget) {
@@ -250,7 +245,7 @@
       throw new IllegalArgumentException(target.toString());
     }
 
-    elem.setAttribute("name", target.getLabel().toString());
+    elem.setAttribute("name", labelPrinter.toString(target.getLabel()));
     String location = FormatUtils.getLocation(target, relativeLocations, displaySourceFileLocation);
     if (!queryOptions.xmlLineNumbers) {
       int firstColon = location.indexOf(':');
@@ -263,16 +258,17 @@
     return elem;
   }
 
-  private static void addPackageGroupsToElement(Document doc, Element parent, Target target) {
+  private static void addPackageGroupsToElement(
+      Document doc, Element parent, Target target, LabelPrinter labelPrinter) {
     for (Label visibilityDependency : target.getVisibility().getDependencyLabels()) {
       Element elem = doc.createElement("package-group");
-      elem.setAttribute("name", visibilityDependency.toString());
+      elem.setAttribute("name", labelPrinter.toString(visibilityDependency));
       parent.appendChild(elem);
     }
 
     for (Label visibilityDeclaration : target.getVisibility().getDeclaredLabels()) {
       Element elem = doc.createElement("visibility-label");
-      elem.setAttribute("name", visibilityDeclaration.toString());
+      elem.setAttribute("name", labelPrinter.toString(visibilityDeclaration));
       parent.appendChild(elem);
     }
   }
@@ -285,32 +281,33 @@
     }
   }
 
-  private void addStarlarkFilesToElement(Document doc, Element parent, InputFile inputFile)
+  private void addStarlarkFilesToElement(
+      Document doc, Element parent, InputFile inputFile, LabelPrinter labelPrinter)
       throws InterruptedException {
     Iterable<Label> dependencies =
         aspectResolver.computeBuildFileDependencies(inputFile.getPackage());
 
     for (Label starlarkFileDep : dependencies) {
       Element elem = doc.createElement("load");
-      elem.setAttribute("name", starlarkFileDep.toString());
+      elem.setAttribute("name", labelPrinter.toString(starlarkFileDep));
       parent.appendChild(elem);
     }
   }
 
   /**
-   * Creates and returns a new DOM tree for the specified attribute values.
-   * For non-configurable attributes, this is a single value. For configurable
-   * attributes, this contains one value for each configuration.
-   * (Only toplevel values are named attributes; list elements are unnamed.)
+   * Creates and returns a new DOM tree for the specified attribute values. For non-configurable
+   * attributes, this is a single value. For configurable attributes, this contains one value for
+   * each configuration. (Only toplevel values are named attributes; list elements are unnamed.)
    *
-   * <p>In the case of configurable attributes, multi-value attributes (e.g. lists)
-   * merge all configured lists into an aggregate flattened list. Single-value attributes
-   * simply refrain to set a value and annotate the DOM element as configurable.
+   * <p>In the case of configurable attributes, multi-value attributes (e.g. lists) merge all
+   * configured lists into an aggregate flattened list. Single-value attributes simply refrain to
+   * set a value and annotate the DOM element as configurable.
    *
-   * <P>(The ungainly qualified class name is required to avoid ambiguity with
+   * <p>(The ungainly qualified class name is required to avoid ambiguity with
    * OutputFormatter.OutputType.)
    */
-  private static Element createValueElement(Document doc, Type<?> type, Iterable<Object> values) {
+  private static Element createValueElement(
+      Document doc, Type<?> type, Iterable<Object> values, LabelPrinter labelPrinter) {
     // "Import static" with method scope:
     Type<?> LABEL_LIST = BuildType.LABEL_LIST;
     Type<?> LICENSE = BuildType.LICENSE;
@@ -323,7 +320,7 @@
       elem = doc.createElement("list");
       for (Object value : values) {
         for (Object elemValue : (Collection<?>) value) {
-          elem.appendChild(createValueElement(doc, elemType, elemValue));
+          elem.appendChild(createValueElement(doc, elemType, elemValue, labelPrinter));
         }
       }
     } else if (type instanceof Type.DictType) {
@@ -335,10 +332,10 @@
           if (visitedValues.add(entry.getKey())) {
             Element pairElem = doc.createElement("pair");
             elem.appendChild(pairElem);
-            pairElem.appendChild(createValueElement(doc,
-                    dictType.getKeyType(), entry.getKey()));
-            pairElem.appendChild(createValueElement(doc,
-                    dictType.getValueType(), entry.getValue()));
+            pairElem.appendChild(
+                createValueElement(doc, dictType.getKeyType(), entry.getKey(), labelPrinter));
+            pairElem.appendChild(
+                createValueElement(doc, dictType.getValueType(), entry.getValue(), labelPrinter));
           }
         }
       }
@@ -347,11 +344,13 @@
       if (!hasMultipleValues) {
         License license = (License) Iterables.getOnlyElement(values);
 
-        Element exceptions = createValueElement(doc, LABEL_LIST, license.getExceptions());
+        Element exceptions =
+            createValueElement(doc, LABEL_LIST, license.getExceptions(), labelPrinter);
         exceptions.setAttribute("name", "exceptions");
         elem.appendChild(exceptions);
 
-        Element licenseTypes = createValueElement(doc, STRING_LIST, license.getLicenseTypes());
+        Element licenseTypes =
+            createValueElement(doc, STRING_LIST, license.getLicenseTypes(), labelPrinter);
         licenseTypes.setAttribute("name", "license-types");
         elem.appendChild(licenseTypes);
       }
@@ -362,7 +361,11 @@
         // Values such as those of attribute "linkstamp" may be null.
         if (value != null) {
           try {
-            elem.setAttribute("value", value.toString());
+            if (value instanceof Label) {
+              elem.setAttribute("value", labelPrinter.toString((Label) value));
+            } else {
+              elem.setAttribute("value", value.toString());
+            }
           } catch (DOMException e) {
             elem.setAttribute("value", "[[[ERROR: could not be encoded as XML]]]");
           }
@@ -372,17 +375,17 @@
     return elem;
   }
 
-  private static Element createValueElement(Document doc, Type<?> type, Object value) {
-    return createValueElement(doc, type, ImmutableList.of(value));
+  private static Element createValueElement(
+      Document doc, Type<?> type, Object value, LabelPrinter labelPrinter) {
+    return createValueElement(doc, type, ImmutableList.of(value), labelPrinter);
   }
 
   /**
-   * Creates the given DOM element, adding <code>configurable="yes"</code> if it represents
-   * a configurable single-value attribute (configurable list attributes simply have their
-   * lists merged into an aggregate flat list).
+   * Creates the given DOM element, adding <code>configurable="yes"</code> if it represents a
+   * configurable single-value attribute (configurable list attributes simply have their lists
+   * merged into an aggregate flat list).
    */
-  private static Element createSingleValueElement(Document doc, String name,
-      boolean configurable) {
+  private static Element createSingleValueElement(Document doc, String name, boolean configurable) {
     Element elem = doc.createElement(name);
     if (configurable) {
       elem.setAttribute("configurable", "yes");
diff --git a/src/main/java/com/google/devtools/build/lib/rules/genquery/BUILD b/src/main/java/com/google/devtools/build/lib/rules/genquery/BUILD
index f9cbb31c..1ceee39 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/genquery/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/rules/genquery/BUILD
@@ -38,6 +38,7 @@
         "//src/main/java/com/google/devtools/build/lib/concurrent",
         "//src/main/java/com/google/devtools/build/lib/events",
         "//src/main/java/com/google/devtools/build/lib/packages",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/pkgcache",
         "//src/main/java/com/google/devtools/build/lib/profiler",
         "//src/main/java/com/google/devtools/build/lib/query2",
diff --git a/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java b/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java
index 6bb4cf1..fadd368 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java
@@ -51,6 +51,7 @@
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.BuildType;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.Package;
@@ -316,21 +317,22 @@
                   RepositoryName.MAIN,
                   repositoryMappingValue.getRepositoryMapping()),
               PathFragment.EMPTY_FRAGMENT,
-              /*keepGoing=*/ false,
+              /* keepGoing= */ false,
               ruleContext.attributes().get("strict", Type.BOOLEAN),
-              /*orderedResults=*/ !graphlessQuery,
+              /* orderedResults= */ !graphlessQuery,
               UniverseScope.EMPTY,
               // Use a single thread to prevent race conditions causing nondeterministic output
               // (b/127644784). All the packages are already loaded at this point, so there is
               // no need to start up multiple threads anyway.
-              /*loadingPhaseThreads=*/ 1,
+              /* loadingPhaseThreads= */ 1,
               packageProvider.getValidTargetPredicate(),
               getEventHandler(ruleContext),
               settings,
-              /*extraFunctions=*/ ImmutableList.of(),
-              /*packagePath=*/ null,
-              /*blockUniverseEvaluationErrors=*/ false,
-              /*useGraphlessQuery=*/ graphlessQuery);
+              /* extraFunctions= */ ImmutableList.of(),
+              /* packagePath= */ null,
+              /* blockUniverseEvaluationErrors= */ false,
+              /* useGraphlessQuery= */ graphlessQuery,
+              LabelPrinter.legacy());
       QueryExpression expr = QueryExpression.parse(query, queryEnvironment);
       formatter.verifyCompatible(queryEnvironment, expr);
       targets =
@@ -369,7 +371,7 @@
           queryOptions.aspectDeps.createResolver(packageProvider, getEventHandler(ruleContext)),
           getEventHandler(ruleContext),
           hashFunction,
-          queryEnvironment.getMainRepoMapping());
+          queryEnvironment.getLabelPrinter());
       outputStream.close();
     } catch (ClosedByInterruptException e) {
       throw new InterruptedException(e.getMessage());
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/BUILD b/src/main/java/com/google/devtools/build/lib/runtime/commands/BUILD
index 1a9e10d..d315dea 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/BUILD
@@ -59,6 +59,8 @@
         "//src/main/java/com/google/devtools/build/lib/exec/local:options",
         "//src/main/java/com/google/devtools/build/lib/packages",
         "//src/main/java/com/google/devtools/build/lib/packages:configured_attribute_mapper",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
+        "//src/main/java/com/google/devtools/build/lib/packages/semantics",
         "//src/main/java/com/google/devtools/build/lib/pkgcache",
         "//src/main/java/com/google/devtools/build/lib/profiler",
         "//src/main/java/com/google/devtools/build/lib/profiler:profiler-output",
@@ -97,6 +99,7 @@
         "//src/main/java/com/google/devtools/build/skyframe",
         "//src/main/java/com/google/devtools/common/options",
         "//src/main/java/com/google/devtools/common/options:invocation_policy",
+        "//src/main/java/net/starlark/java/eval",
         "//src/main/protobuf:bazel_flags_java_proto",
         "//src/main/protobuf:command_server_java_proto",
         "//src/main/protobuf:extra_actions_base_java_proto",
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java
index c7d6206..25131d8 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java
@@ -186,7 +186,7 @@
               queryOptions.aspectDeps.createResolver(env.getPackageManager(), env.getReporter()),
               env.getReporter(),
               hashFunction,
-              queryEnv.getMainRepoMapping());
+              queryEnv.getLabelPrinter());
         } catch (ClosedByInterruptException | InterruptedException e) {
           return reportAndCreateInterruptedResult(env);
         } catch (IOException e) {
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryEnvironmentBasedCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryEnvironmentBasedCommand.java
index d5b2817..3c06325 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryEnvironmentBasedCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryEnvironmentBasedCommand.java
@@ -23,7 +23,9 @@
 import com.google.devtools.build.lib.cmdline.TargetPattern;
 import com.google.devtools.build.lib.cmdline.TargetPattern.Parser;
 import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions;
 import com.google.devtools.build.lib.profiler.ProfilePhase;
 import com.google.devtools.build.lib.profiler.Profiler;
 import com.google.devtools.build.lib.query2.common.AbstractBlazeQueryEnvironment;
@@ -62,6 +64,7 @@
 import com.google.devtools.common.options.TriState;
 import java.util.Set;
 import java.util.function.Function;
+import net.starlark.java.eval.StarlarkSemantics;
 
 /**
  * Common methods and utils to set up Blaze Runtime environments for {@link BlazeCommand} which
@@ -155,6 +158,14 @@
           Query.Code.GRAPHLESS_PREREQ_UNMET);
     }
 
+    StarlarkSemantics starlarkSemantics =
+        env.getSkyframeExecutor()
+            .getEffectiveStarlarkSemantics(env.getOptions().getOptions(BuildLanguageOptions.class));
+    LabelPrinter labelPrinter =
+        env.getOptions()
+            .getOptions(QueryOptions.class)
+            .getLabelPrinter(starlarkSemantics, mainRepoTargetParser.getRepoMapping());
+
     try (QueryRuntimeHelper queryRuntimeHelper =
         env.getRuntime().getQueryRuntimeHelperFactory().create(env)) {
       Either<BlazeCommandResult, QueryEvalResult> result;
@@ -169,7 +180,8 @@
               threadsOption.threads,
               settings,
               useGraphlessQuery,
-              mainRepoTargetParser)) {
+              mainRepoTargetParser,
+              labelPrinter)) {
         result =
             doQuery(
                 query, env, queryOptions, streamResults, formatter, queryEnv, queryRuntimeHelper);
@@ -232,7 +244,8 @@
       int loadingPhaseThreads,
       Set<Setting> settings,
       boolean useGraphlessQuery,
-      TargetPattern.Parser mainRepoTargetParser) {
+      TargetPattern.Parser mainRepoTargetParser,
+      LabelPrinter labelPrinter) {
 
     WalkableGraph walkableGraph =
         SkyframeExecutorWrappingWalkableGraph.of(env.getSkyframeExecutor());
@@ -258,17 +271,18 @@
             mainRepoTargetParser,
             env.getRelativeWorkingDirectory(),
             keepGoing,
-            /*strictScope=*/ true,
+            /* strictScope= */ true,
             orderedResults,
             universeScope,
             loadingPhaseThreads,
-            /*labelFilter=*/ ALL_LABELS,
+            /* labelFilter= */ ALL_LABELS,
             env.getReporter(),
             settings,
             env.getRuntime().getQueryFunctions(),
             env.getPackageManager().getPackagePath(),
-            /*blockUniverseEvaluationErrors=*/ false,
-            useGraphlessQuery);
+            /* blockUniverseEvaluationErrors= */ false,
+            useGraphlessQuery,
+            labelPrinter);
   }
 
   private static BlazeCommandResult reportAndCreateInterruptResult(
diff --git a/src/test/java/com/google/devtools/build/lib/query2/aquery/ActionGraphQueryHelper.java b/src/test/java/com/google/devtools/build/lib/query2/aquery/ActionGraphQueryHelper.java
index dafe469..1fecf40 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/aquery/ActionGraphQueryHelper.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/aquery/ActionGraphQueryHelper.java
@@ -14,6 +14,7 @@
 package com.google.devtools.build.lib.query2.aquery;
 
 import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.query2.PostAnalysisQueryEnvironment;
 import com.google.devtools.build.lib.query2.PostAnalysisQueryEnvironment.TopLevelConfigurations;
 import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryFunction;
@@ -42,7 +43,8 @@
         mainRepoTargetParser,
         analysisHelper.getPackageManager().getPackagePath(),
         () -> walkableGraph,
-        settings);
+        settings,
+        LabelPrinter.legacy());
   }
 
   @Override
diff --git a/src/test/java/com/google/devtools/build/lib/query2/aquery/BUILD b/src/test/java/com/google/devtools/build/lib/query2/aquery/BUILD
index 9fc728a..ea561ab 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/aquery/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/query2/aquery/BUILD
@@ -15,6 +15,8 @@
     testonly = 1,
     srcs = ["ActionGraphQueryHelper.java"],
     deps = [
+        "//src/main/java/com/google/devtools/build/lib/analysis:configured_target_value",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/query2",
         "//src/main/java/com/google/devtools/build/lib/query2/engine",
         "//src/main/java/com/google/devtools/build/skyframe",
diff --git a/src/test/java/com/google/devtools/build/lib/query2/cquery/BUILD b/src/test/java/com/google/devtools/build/lib/query2/cquery/BUILD
index f89a548..96ba9a4 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/cquery/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/query2/cquery/BUILD
@@ -20,6 +20,7 @@
         ":configured_target_query_test",
         "//src/main/java/com/google/devtools/build/lib/events",
         "//src/main/java/com/google/devtools/build/lib/packages",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/query2",
         "//src/main/java/com/google/devtools/build/lib/query2/engine",
         "//src/main/java/com/google/devtools/build/lib/query2/query/aspectresolvers",
@@ -41,6 +42,7 @@
         ":configured_target_query_test",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/events",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/query2",
         "//src/main/java/com/google/devtools/build/lib/query2/engine",
         "//third_party:guava",
@@ -84,6 +86,8 @@
     testonly = 1,
     srcs = ["ConfiguredTargetQueryHelper.java"],
     deps = [
+        "//src/main/java/com/google/devtools/build/lib/analysis:configured_target",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/query2",
         "//src/main/java/com/google/devtools/build/lib/query2/engine",
         "//src/main/java/com/google/devtools/build/skyframe",
@@ -126,6 +130,7 @@
         "//src/main/java/com/google/devtools/build/lib/analysis:config/execution_transition_factory",
         "//src/main/java/com/google/devtools/build/lib/events",
         "//src/main/java/com/google/devtools/build/lib/packages",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/query2",
         "//src/main/java/com/google/devtools/build/lib/query2/engine",
         "//src/main/java/com/google/devtools/build/lib/query2/query/aspectresolvers",
@@ -154,6 +159,7 @@
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/events",
         "//src/main/java/com/google/devtools/build/lib/packages",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/query2",
         "//src/main/java/com/google/devtools/build/lib/query2/engine",
         "//src/main/java/com/google/devtools/build/lib/util:filetype",
diff --git a/src/test/java/com/google/devtools/build/lib/query2/cquery/BuildOutputFormatterCallbackTest.java b/src/test/java/com/google/devtools/build/lib/query2/cquery/BuildOutputFormatterCallbackTest.java
index 949eaa3..bdc3954 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/cquery/BuildOutputFormatterCallbackTest.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/cquery/BuildOutputFormatterCallbackTest.java
@@ -22,6 +22,7 @@
 import com.google.devtools.build.lib.analysis.util.MockRule;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.Reporter;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.query2.PostAnalysisQueryEnvironment;
 import com.google.devtools.build.lib.query2.engine.QueryEnvironment.Setting;
 import com.google.devtools.build.lib.query2.engine.QueryExpression;
@@ -83,7 +84,8 @@
             options,
             new PrintStream(output),
             getHelper().getSkyframeExecutor(),
-            env.getAccessor());
+            env.getAccessor(),
+            LabelPrinter.legacy());
     env.evaluateQuery(expression, callback);
     return Arrays.asList(output.toString().split(System.lineSeparator()));
   }
diff --git a/src/test/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryHelper.java b/src/test/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryHelper.java
index 2353fa5..520b135 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryHelper.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryHelper.java
@@ -15,6 +15,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.analysis.util.AnalysisTestCase;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.query2.PostAnalysisQueryEnvironment.TopLevelConfigurations;
 import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryFunction;
 import com.google.devtools.build.lib.query2.testutil.AbstractQueryTest.QueryHelper;
@@ -50,7 +51,8 @@
         analysisHelper.getPackageManager().getPackagePath(),
         () -> walkableGraph,
         this.settings,
-        null);
+        null,
+        LabelPrinter.legacy());
   }
 
   @Override
diff --git a/src/test/java/com/google/devtools/build/lib/query2/cquery/GraphOutputFormatterCallbackTest.java b/src/test/java/com/google/devtools/build/lib/query2/cquery/GraphOutputFormatterCallbackTest.java
index e90a831..0e8ee92 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/cquery/GraphOutputFormatterCallbackTest.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/cquery/GraphOutputFormatterCallbackTest.java
@@ -17,9 +17,9 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.eventbus.EventBus;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.Reporter;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.query2.PostAnalysisQueryEnvironment;
 import com.google.devtools.build.lib.query2.engine.QueryEnvironment.Setting;
 import com.google.devtools.build.lib.query2.engine.QueryExpression;
@@ -82,7 +82,7 @@
             getHelper().getSkyframeExecutor(),
             env.getAccessor(),
             ct -> env.getFwdDeps(ImmutableList.of(ct)),
-            RepositoryMapping.ALWAYS_FALLBACK);
+            LabelPrinter.legacy());
     env.evaluateQuery(expression, callback);
     return Arrays.asList(output.toString().split(System.lineSeparator()));
   }
diff --git a/src/test/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallbackTest.java b/src/test/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallbackTest.java
index 40a0910..a0a4f8c 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallbackTest.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallbackTest.java
@@ -28,6 +28,7 @@
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.NullEventHandler;
 import com.google.devtools.build.lib.events.Reporter;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.query2.PostAnalysisQueryEnvironment;
 import com.google.devtools.build.lib.query2.cquery.CqueryOptions.Transitions;
 import com.google.devtools.build.lib.query2.cquery.ProtoOutputFormatterCallback.OutputType;
@@ -329,7 +330,8 @@
             options.aspectDeps.createResolver(
                 getHelper().getPackageManager(), NullEventHandler.INSTANCE),
             OutputType.BINARY,
-            /*trimmingTransitionFactory=*/ null);
+            /*trimmingTransitionFactory=*/ null,
+            LabelPrinter.legacy());
     env.evaluateQuery(expression, callback);
     return callback.getProtoResult();
   }
diff --git a/src/test/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterTest.java b/src/test/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterTest.java
index 802073e..34a4da2 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterTest.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterTest.java
@@ -24,9 +24,9 @@
 import com.google.devtools.build.lib.analysis.config.transitions.NoTransition;
 import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
 import com.google.devtools.build.lib.analysis.util.MockRule;
-import com.google.devtools.build.lib.cmdline.RepositoryMapping;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.Reporter;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.RuleTransitionData;
 import com.google.devtools.build.lib.query2.PostAnalysisQueryEnvironment;
 import com.google.devtools.build.lib.query2.cquery.CqueryOptions.Transitions;
@@ -247,7 +247,7 @@
             env.getAccessor(),
             env.getHostConfiguration(),
             trimmingTransitionFactory,
-            RepositoryMapping.ALWAYS_FALLBACK);
+            LabelPrinter.legacy());
     env.evaluateQuery(env.transformParsedQuery(QueryParser.parse(queryExpression, env)), callback);
     return callback.getResult();
   }
diff --git a/src/test/java/com/google/devtools/build/lib/query2/engine/BUILD b/src/test/java/com/google/devtools/build/lib/query2/engine/BUILD
index 1de3718..8a5c391 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/engine/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/query2/engine/BUILD
@@ -22,6 +22,7 @@
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/events",
         "//src/main/java/com/google/devtools/build/lib/packages",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/pkgcache",
         "//src/main/java/com/google/devtools/build/lib/query2",
         "//src/main/java/com/google/devtools/build/lib/query2/common:QueryTransitivePackagePreloader",
diff --git a/src/test/java/com/google/devtools/build/lib/query2/engine/GraphlessQueryTest.java b/src/test/java/com/google/devtools/build/lib/query2/engine/GraphlessQueryTest.java
index 973376b..528d043 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/engine/GraphlessQueryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/engine/GraphlessQueryTest.java
@@ -23,6 +23,7 @@
 import com.google.devtools.build.lib.cmdline.TargetPattern;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.CachingPackageLocator;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.PackageFactory.EnvironmentExtension;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.packages.util.MockToolsConfig;
@@ -130,7 +131,8 @@
               Iterable<QueryFunction> extraFunctions,
               @Nullable PathPackageLocator packagePath,
               boolean blockUniverseEvaluationErrors,
-              boolean useGraphlessQuery) {
+              boolean useGraphlessQuery,
+              LabelPrinter labelPrinter) {
             return new GraphlessBlazeQueryEnvironment(
                 queryTransitivePackagePreloader,
                 targetProvider,
@@ -143,7 +145,8 @@
                 labelFilter,
                 eventHandler,
                 settings,
-                extraFunctions);
+                extraFunctions,
+                labelPrinter);
           }
         };
       }
diff --git a/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD b/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD
index 8745c75..bd80a59 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD
@@ -33,6 +33,7 @@
         "//src/main/java/com/google/devtools/build/lib/events",
         "//src/main/java/com/google/devtools/build/lib/graph",
         "//src/main/java/com/google/devtools/build/lib/packages",
+        "//src/main/java/com/google/devtools/build/lib/packages:label_printer",
         "//src/main/java/com/google/devtools/build/lib/packages/semantics",
         "//src/main/java/com/google/devtools/build/lib/pkgcache",
         "//src/main/java/com/google/devtools/build/lib/query2",
diff --git a/src/test/java/com/google/devtools/build/lib/query2/testutil/SkyframeQueryHelper.java b/src/test/java/com/google/devtools/build/lib/query2/testutil/SkyframeQueryHelper.java
index 5159f9f..9ec8694 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/testutil/SkyframeQueryHelper.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/testutil/SkyframeQueryHelper.java
@@ -38,6 +38,7 @@
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.cmdline.RepositoryName;
 import com.google.devtools.build.lib.packages.ConstantRuleVisibility;
+import com.google.devtools.build.lib.packages.LabelPrinter;
 import com.google.devtools.build.lib.packages.PackageFactory;
 import com.google.devtools.build.lib.packages.PackageFactory.EnvironmentExtension;
 import com.google.devtools.build.lib.packages.Target;
@@ -223,19 +224,20 @@
         pkgManager,
         targetParser,
         mainRepoTargetParser,
-        /*relativeWorkingDirectory=*/ PathFragment.EMPTY_FRAGMENT,
+        /* relativeWorkingDirectory= */ PathFragment.EMPTY_FRAGMENT,
         keepGoing,
-        /*strictScope=*/ true,
+        /* strictScope= */ true,
         orderedResults,
         universeScope,
-        /*loadingPhaseThreads=*/ 1,
-        /*labelFilter=*/ ALL_LABELS,
+        /* loadingPhaseThreads= */ 1,
+        /* labelFilter= */ ALL_LABELS,
         getReporter(),
         this.settings,
         getExtraQueryFunctions(),
         pkgManager.getPackagePath(),
         blockUniverseEvaluationErrors,
-        /*useGraphlessQuery=*/ false);
+        /* useGraphlessQuery= */ false,
+        LabelPrinter.legacy());
   }
 
   protected abstract Iterable<QueryFunction> getExtraQueryFunctions();
diff --git a/src/test/py/bazel/bzlmod/bzlmod_query_test.py b/src/test/py/bazel/bzlmod/bzlmod_query_test.py
index 3b3e351..a19668a 100644
--- a/src/test/py/bazel/bzlmod/bzlmod_query_test.py
+++ b/src/test/py/bazel/bzlmod/bzlmod_query_test.py
@@ -15,6 +15,7 @@
 """Tests bzlmod integration inside query (querying and external repo using the repo mapping)."""
 
 import os
+import re
 import tempfile
 import unittest
 
@@ -83,6 +84,90 @@
     self.assertListEqual(
         ['//:main', '@my_repo//:lib_aaa', '@@ccc~1.2//:lib_ccc'], stdout)
 
+  def testQueryModuleRepoTransitiveDeps_consistentLabels(self):
+    self.ScratchFile(
+        'MODULE.bazel',
+        [
+            'bazel_dep(name = "aaa", version = "1.0", repo_name = "my_repo")',
+        ],
+    )
+    self.ScratchFile(
+        'BUILD',
+        [
+            'cc_binary(',
+            '  name = "main",',
+            '  srcs = ["main.cc"],',
+            '  deps = ["@my_repo//:lib_aaa"],',
+            ')',
+        ],
+    )
+    _, stdout, _ = self.RunBazel([
+        'query',
+        'kind("cc_.* rule", deps(//:main))',
+        '--noimplicit_deps',
+        '--notool_deps',
+        '--consistent_labels',
+    ])
+    self.assertListEqual(
+        ['@@//:main', '@@aaa~1.0//:lib_aaa', '@@ccc~1.2//:lib_ccc'], stdout
+    )
+
+  def testQueryModuleRepoTransitiveDeps_consistentLabels_outputPackage(self):
+    self.ScratchFile(
+        'MODULE.bazel',
+        [
+            'bazel_dep(name = "aaa", version = "1.0", repo_name = "my_repo")',
+        ],
+    )
+    self.ScratchFile(
+        'pkg/BUILD',
+        [
+            'cc_binary(',
+            '  name = "main",',
+            '  srcs = ["main.cc"],',
+            '  deps = ["@my_repo//:lib_aaa"],',
+            ')',
+        ],
+    )
+    _, stdout, _ = self.RunBazel([
+        'query',
+        'kind("cc_.* rule", deps(//pkg:main))',
+        '--noimplicit_deps',
+        '--notool_deps',
+        '--consistent_labels',
+        '--output=package',
+    ])
+    self.assertListEqual(['@@//pkg', '@@aaa~1.0//', '@@ccc~1.2//'], stdout)
+
+  def testQueryModuleRepoTransitiveDeps_consistentLabels_outputBuild(self):
+    self.ScratchFile(
+        'MODULE.bazel',
+        [
+            'bazel_dep(name = "aaa", version = "1.0", repo_name = "my_repo")',
+        ],
+    )
+    self.ScratchFile(
+        'pkg/BUILD',
+        [
+            'cc_binary(',
+            '  name = "main",',
+            '  srcs = ["main.cc"],',
+            '  deps = ["@my_repo//:lib_aaa"],',
+            ')',
+        ],
+    )
+    _, stdout, _ = self.RunBazel([
+        'query',
+        'kind("cc_.* rule", deps(//pkg:main))',
+        '--noimplicit_deps',
+        '--notool_deps',
+        '--consistent_labels',
+        '--output=build',
+    ])
+    # Verify that there are no non-canonical labels in the output.
+    stdout = '\n'.join(stdout)
+    self.assertEqual(len(re.findall('(?<!@)@[a-z0-9.~]*//', stdout)), 0, stdout)
+
   def testAqueryModuleRepoTargetsBelow(self):
     self.ScratchFile('MODULE.bazel', [
         'bazel_dep(name = "aaa", version = "1.0", repo_name = "my_repo")',
@@ -117,6 +202,34 @@
     self.assertIn('Target: @my_repo//:lib_aaa', stdout)
     self.assertIn('Target: @@ccc~1.2//:lib_ccc', stdout)
 
+  def testAqueryModuleRepoTransitiveDeps_consistentLabels(self):
+    self.ScratchFile(
+        'MODULE.bazel',
+        [
+            'bazel_dep(name = "aaa", version = "1.0", repo_name = "my_repo")',
+        ],
+    )
+    self.ScratchFile(
+        'BUILD',
+        [
+            'cc_binary(',
+            '  name = "main",',
+            '  srcs = ["main.cc"],',
+            '  deps = ["@my_repo//:lib_aaa"],',
+            ')',
+        ],
+    )
+    _, stdout, _ = self.RunBazel([
+        'aquery',
+        'kind("cc_.* rule", deps(//:main))',
+        '--noimplicit_deps',
+        '--notool_deps',
+        '--consistent_labels',
+    ])
+    self.assertIn('Target: @@//:main', stdout)
+    self.assertIn('Target: @@aaa~1.0//:lib_aaa', stdout)
+    self.assertIn('Target: @@ccc~1.2//:lib_ccc', stdout)
+
   def testCqueryModuleRepoTargetsBelow(self):
     self.ScratchFile('MODULE.bazel', [
         'bazel_dep(name = "aaa", version = "1.0", repo_name = "my_repo")',
@@ -149,6 +262,35 @@
     self.assertRegex(stdout[2], r'^@@ccc~1.2//:lib_ccc \([\w\d]+\)$')
     self.assertEqual(len(stdout), 3)
 
+  def testCqueryModuleRepoTransitiveDeps_consistentLabels(self):
+    self.ScratchFile(
+        'MODULE.bazel',
+        [
+            'bazel_dep(name = "aaa", version = "1.0", repo_name = "my_repo")',
+        ],
+    )
+    self.ScratchFile(
+        'BUILD',
+        [
+            'cc_binary(',
+            '  name = "main",',
+            '  srcs = ["main.cc"],',
+            '  deps = ["@my_repo//:lib_aaa"],',
+            ')',
+        ],
+    )
+    _, stdout, _ = self.RunBazel([
+        'cquery',
+        'kind("cc_.* rule", deps(//:main))',
+        '--noimplicit_deps',
+        '--notool_deps',
+        '--consistent_labels',
+    ])
+    self.assertRegex(stdout[0], r'^@@//:main \([\w\d]+\)$')
+    self.assertRegex(stdout[1], r'^@@aaa~1.0//:lib_aaa \([\w\d]+\)$')
+    self.assertRegex(stdout[2], r'^@@ccc~1.2//:lib_ccc \([\w\d]+\)$')
+    self.assertEqual(len(stdout), 3)
+
   def testFetchModuleRepoTargetsBelow(self):
     self.ScratchFile('MODULE.bazel', [
         'bazel_dep(name = "aaa", version = "1.0", repo_name = "my_repo")',
@@ -172,7 +314,7 @@
     self.assertIsNotNone(output_file)
     output = output_file.readlines()
     output_file.close()
-    self.assertListEqual(['@my_repo//:lib_aaa\n'], output)
+    self.assertListEqual(['@aaa~1.0//:lib_aaa\n'], output)
 
   def testQueryCannotResolveRepoMapping_malformedModuleFile(self):
     self.ScratchFile('MODULE.bazel', [
diff --git a/src/test/shell/integration/configured_query_test.sh b/src/test/shell/integration/configured_query_test.sh
index 615296b..858b125 100755
--- a/src/test/shell/integration/configured_query_test.sh
+++ b/src/test/shell/integration/configured_query_test.sh
@@ -881,8 +881,17 @@
     --starlark:expr="str(target.label) + '%foo'" > output \
     2>"$TEST_log" || fail "Expected success"
 
-  assert_contains "//$pkg:pylib%foo" output
-  assert_contains "//$pkg:pylibtwo%foo" output
+  assert_contains "^@//$pkg:pylib%foo$" output
+  assert_contains "^@//$pkg:pylibtwo%foo$" output
+
+  bazel cquery "//$pkg:all" --output=starlark \
+    --noincompatible_unambiguous_label_stringification \
+    --starlark:expr="str(target.label) + '%foo'" > output \
+    2>"$TEST_log" || fail "Expected success"
+
+  # Verify use of the effective rather than default Starlark semantics.
+  assert_contains "^//$pkg:pylib%foo$" output
+  assert_contains "^//$pkg:pylibtwo%foo$" output
 
   # Test that the default for --starlark:expr str(target.label)
   bazel cquery "//$pkg:all" --output=starlark >output \