If a header is in multiple targets, take it as part of the first target (lexicographically).

This is not Good Behavior. In particular, this means that adding a dependency can break Rust callers. Consider the following:

```cc
//h1.h
struct S {};
```

```cc
//h2.h
void Foo(S s);
```

with this BUILD file:

```py
cc_library(name="h1_a", hdrs=["h1.h"], ...)
cc_library(name="h1_b", hdrs=["h1.h"], ...)

cc_library(name="h2_a", hdrs=["h2.h"], deps=[":h1_a"])
cc_library(name="h2_b", hdrs=["h2.h"], deps=[":h1_b"])
cc_library(name="h2_ab", hdrs=["h2.h"], deps=[":h1_a", ":h1_b"])
```

Then:

* `h2_a` contains `fn Foo(s: h1_a::S);`
* `h2_b` contains `fn Foo(s: h2_a::S);`
* `h2_ab` contains `fn Foo(s: h1_a::S);`

Meaning that adding a single (TRANSITIVE) dependency can accidentally change the type of your parameters, breaking Rust callers -- a caller who was passing `h2_a::S` would get broken if a transitive dependency on `h1_a` were added.

But note: without this CL, we're even _worse_ off, because that same transitive dependency breaks the build entirely, and there is no way to resolve it. After this CL, there is a quick fix: use `h1_a::S`.

---

Alternatives considered:

* We could fix all headers everywhere to have a single canonical build target, but this is a big task. We do likely want to do it eventually, but it shouldn't block early adopters from trying Crubit.

---

It's worth noting that with the proposed[]

PiperOrigin-RevId: 501900537
diff --git a/rs_bindings_from_cc/BUILD b/rs_bindings_from_cc/BUILD
index 727d035..2389c72 100644
--- a/rs_bindings_from_cc/BUILD
+++ b/rs_bindings_from_cc/BUILD
@@ -172,6 +172,7 @@
         "//common:status_macros",
         "@absl//absl/container:flat_hash_map",
         "@absl//absl/flags:flag",
+        "@absl//absl/log",
         "@absl//absl/status:statusor",
         "@absl//absl/strings",
         "@llvm-project//llvm:Support",
diff --git a/rs_bindings_from_cc/cmdline.cc b/rs_bindings_from_cc/cmdline.cc
index aeabfce..fe6b7c7 100644
--- a/rs_bindings_from_cc/cmdline.cc
+++ b/rs_bindings_from_cc/cmdline.cc
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "absl/flags/flag.h"
+#include "absl/log/log.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/substitute.h"
 #include "common/status_macros.h"
@@ -187,13 +188,19 @@
             "Expected `h` fields of `--targets_and_headers` to be an array of "
             "non-empty strings");
       }
-      const auto [it, inserted] = cmdline.headers_to_targets_.insert(
-          std::make_pair(HeaderName(header), BazelLabel(target)));
+      BazelLabel target_label(target);
+      auto [it, inserted] = cmdline.headers_to_targets_.try_emplace(
+          HeaderName(header), std::move(target_label));
       if (!inserted) {
-        return absl::InvalidArgumentError(absl::Substitute(
-            "The `--targets_and_headers` cmdline argument assigns "
-            "`$0` header to two conflicting targets: `$1` vs `$2`",
-            header, target, it->second.value()));
+        LOG(WARNING) << "The `--targets_and_headers` cmdline argument assigns "
+                        "`"
+                     << header << "` header to two conflicting targets: `"
+                     << target << "` vs `" << it->second.value() << "`";
+        // Assign the one that comes first alphabetically, to get a consistent
+        // result.
+        if (target_label.value() < it->second.value()) {
+          it->second = std::move(target_label);
+        }
       }
     }
   }
diff --git a/rs_bindings_from_cc/cmdline.h b/rs_bindings_from_cc/cmdline.h
index 2994b29..2f1f7d6 100644
--- a/rs_bindings_from_cc/cmdline.h
+++ b/rs_bindings_from_cc/cmdline.h
@@ -77,8 +77,8 @@
 
   const BazelLabel& current_target() const { return current_target_; }
 
-  const absl::flat_hash_map<const HeaderName, const BazelLabel>&
-  headers_to_targets() const {
+  const absl::flat_hash_map<HeaderName, BazelLabel>& headers_to_targets()
+      const {
     return headers_to_targets_;
   }
 
@@ -110,7 +110,7 @@
 
   BazelLabel current_target_;
   std::vector<HeaderName> public_headers_;
-  absl::flat_hash_map<const HeaderName, const BazelLabel> headers_to_targets_;
+  absl::flat_hash_map<HeaderName, BazelLabel> headers_to_targets_;
 
   std::vector<std::string> extra_rs_srcs_;
 
diff --git a/rs_bindings_from_cc/cmdline_test.cc b/rs_bindings_from_cc/cmdline_test.cc
index 0f59e9e..26e8406 100644
--- a/rs_bindings_from_cc/cmdline_test.cc
+++ b/rs_bindings_from_cc/cmdline_test.cc
@@ -146,14 +146,20 @@
 }
 
 TEST(CmdlineTest, TargetsAndHeadersDuplicateHeader) {
-  constexpr absl::string_view kTestInput = R"([
+  constexpr absl::string_view kHeaders = R"([
       {"t": "t1", "h": ["h1"]},
-      {"t": "t2", "h": ["h1"]} ])";
-  ASSERT_THAT(
-      TestCmdline({"h1"}, std::string(kTestInput)),
-      StatusIs(absl::StatusCode::kInvalidArgument,
-               AllOf(HasSubstr("--targets_and_headers"), HasSubstr("conflict"),
-                     HasSubstr("h1"), HasSubstr("t1"), HasSubstr("t2"))));
+      {"t": "t2", "h": ["h1", "h2"]} ])";
+  ASSERT_OK_AND_ASSIGN(
+      Cmdline cmdline,
+      Cmdline::CreateForTesting(
+          "cc_out", "rs_out", "ir_out", "namespaces_out", "crubit_support_path",
+          "clang_format_exe_path", "rustfmt_exe_path", "rustfmt_config_path",
+          /* do_nothing= */ false, {"h1"}, std::string(kHeaders),
+          {"extra_file.rs"}, {"scan_for_instantiations.rs"},
+          "instantiations_out", "error_report_out"));
+  EXPECT_THAT(cmdline.headers_to_targets(),
+              UnorderedElementsAre(Pair(HeaderName("h1"), BazelLabel("t1")),
+                                   Pair(HeaderName("h2"), BazelLabel("t2"))));
 }
 
 TEST(CmdlineTest, PublicHeadersEmpty) {
diff --git a/rs_bindings_from_cc/decl_importer.h b/rs_bindings_from_cc/decl_importer.h
index b8b1277..94ab8de 100644
--- a/rs_bindings_from_cc/decl_importer.h
+++ b/rs_bindings_from_cc/decl_importer.h
@@ -20,8 +20,7 @@
 class Invocation {
  public:
   Invocation(BazelLabel target, absl::Span<const HeaderName> public_headers,
-             const absl::flat_hash_map<const HeaderName, const BazelLabel>&
-                 header_targets)
+             const absl::flat_hash_map<HeaderName, BazelLabel>& header_targets)
       : target_(target),
         public_headers_(public_headers),
         lifetime_context_(std::make_shared<
@@ -57,8 +56,7 @@
   IR ir_;
 
  private:
-  const absl::flat_hash_map<const HeaderName, const BazelLabel>&
-      header_targets_;
+  const absl::flat_hash_map<HeaderName, BazelLabel>& header_targets_;
 };
 
 // Explicitly defined interface that defines how `DeclImporter`s are allowed to
diff --git a/rs_bindings_from_cc/ir_from_cc.cc b/rs_bindings_from_cc/ir_from_cc.cc
index 76660d4..4fff0ac 100644
--- a/rs_bindings_from_cc/ir_from_cc.cc
+++ b/rs_bindings_from_cc/ir_from_cc.cc
@@ -36,7 +36,7 @@
     absl::Span<const HeaderName> public_headers,
     absl::flat_hash_map<const HeaderName, const std::string>
         virtual_headers_contents_for_testing,
-    absl::flat_hash_map<const HeaderName, const BazelLabel> headers_to_targets,
+    absl::flat_hash_map<HeaderName, BazelLabel> headers_to_targets,
     absl::Span<const std::string> extra_rs_srcs,
     absl::Span<const absl::string_view> clang_args,
     absl::Span<const std::string> extra_instantiations) {
diff --git a/rs_bindings_from_cc/ir_from_cc.h b/rs_bindings_from_cc/ir_from_cc.h
index 8ceff69..9dc7345 100644
--- a/rs_bindings_from_cc/ir_from_cc.h
+++ b/rs_bindings_from_cc/ir_from_cc.h
@@ -51,8 +51,7 @@
     absl::Span<const HeaderName> public_headers = {},
     absl::flat_hash_map<const HeaderName, const std::string>
         virtual_headers_contents_for_testing = {},
-    absl::flat_hash_map<const HeaderName, const BazelLabel> headers_to_targets =
-        {},
+    absl::flat_hash_map<HeaderName, BazelLabel> headers_to_targets = {},
     absl::Span<const std::string> extra_rs_srcs = {},
     absl::Span<const absl::string_view> clang_args = {},
     absl::Span<const std::string> extra_instantiations = {});