Allow starlark string flags to mark themselves as allowMultiple.

Duplicate values are not proactively removed. Order is maintained. Values are stored in the BuildOptions starlark options map as a list of strings.

Along the way implement a local cache of build setting targets so we don't repeatedly load them if they're set more than once.

PiperOrigin-RevId: 346798536
diff --git a/src/test/java/com/google/devtools/build/lib/starlark/StarlarkOptionsParsingTest.java b/src/test/java/com/google/devtools/build/lib/starlark/StarlarkOptionsParsingTest.java
index aba35319..fa9636c 100644
--- a/src/test/java/com/google/devtools/build/lib/starlark/StarlarkOptionsParsingTest.java
+++ b/src/test/java/com/google/devtools/build/lib/starlark/StarlarkOptionsParsingTest.java
@@ -411,4 +411,27 @@
                 .getOriginalTargetPattern())
         .containsExactly("//blah:mylib", "//test:my_int_setting");
   }
+
+  @Test
+  @SuppressWarnings("unchecked")
+  public void testAllowMultipleStringFlag() throws Exception {
+    scratch.file(
+        "test/build_setting.bzl",
+        "def _build_setting_impl(ctx):",
+        "  return []",
+        "allow_multiple_flag = rule(",
+        "  implementation = _build_setting_impl,",
+        "  build_setting = config.string(flag=True, allow_multiple=True)",
+        ")");
+    scratch.file(
+        "test/BUILD",
+        "load('//test:build_setting.bzl', 'allow_multiple_flag')",
+        "allow_multiple_flag(name = 'cats', build_setting_default = 'tabby')");
+
+    OptionsParsingResult result = parseStarlarkOptions("--//test:cats=calico --//test:cats=bengal");
+
+    assertThat(result.getStarlarkOptions().keySet()).containsExactly("//test:cats");
+    assertThat((List<String>) result.getStarlarkOptions().get("//test:cats"))
+        .containsExactly("calico", "bengal");
+  }
 }