Repository: rust-lang/cargo (rust)

Issue:
warning: output filename collision.
### Problem

Got lots of warnings like below
```
warning: output filename collision.
The lib target `cfg_if` in package `cfg-if v1.0.0` has the same output filename as the lib target `cfg_if` in package `cfg-if v1.0.0`.
Colliding filename is: target/debug/deps/libcfg_if-b07c5e93d2d15f7e.rlib
The targets should have unique names.
Consider changing their names to be unique or compiling them separately.
This may become a hard error in the future; see <https://github.com/rust-lang/cargo/issues/6313>.
```

### Steps

no warnings:
- stable
- cargo 1.81.0-nightly (a515d4634 2024-07-02)

warnings:
- cargo 1.81.0-nightly (154fdac39 2024-07-07) start to pop up warnings.

### Possible Solution(s)

_No response_

### Notes

### Version

```text
nightly-x86_64-apple-darwin
```


Pull request:
fix: -Cmetadata includes whether extra rustflags is same as host
### What does this PR try to resolve?

Fixes #14253

The root cause is described in <https://github.com/rust-lang/cargo/issues/14253#issuecomment-2299595480>:

> `-Ztarget-applies-to-host --config target-applies-to-host=false` make it possible to build two units for the same output directory with different rustflags (one with artifact/target rustflags, one with none/host rust flags). Those flags aren't included in the `-Cmetadata` hash which is used to disambiguate different versions of crates, resulting in a conflict. The actual error being produced appears to be the result of two invocations of `rustc` racing and clobbering each other…

While we don't hash RUSTFLAGS because it may contain absolute paths that
hurts reproducibility, we track whether a unit's RUSTFLAGS is from host
config, so that we can generate a different metadata hash for runtime
and compile-time units.



### How should we test and review this PR?


This hack is only enabled when `target-applies-to-host=false` and when compile kind is the host platform, so the shouldn't affect any stable behavior.

<!-- homu-ignore:start -->

### Additional information

cc @gmorenz

I found time working on this PR before my travel. Feel free to cherry pick and create a new PR if this is not correct.
<!-- homu-ignore:end -->


Patch:
diff --git a/src/cargo/core/compiler/build_runner/compilation_files.rs b/src/cargo/core/compiler/build_runner/compilation_files.rs
index cad6f0db7..667cf0379 100644
--- a/src/cargo/core/compiler/build_runner/compilation_files.rs
+++ b/src/cargo/core/compiler/build_runner/compilation_files.rs
@@ -649,6 +649,26 @@ fn compute_metadata(
     // with user dependencies.
     unit.is_std.hash(&mut hasher);
 
+    // While we don't hash RUSTFLAGS because it may contain absolute paths that
+    // hurts reproducibility, we track whether a unit's RUSTFLAGS is from host
+    // config, so that we can generate a different metadata hash for runtime
+    // and compile-time units.
+    //
+    // HACK: This is a temporary hack for fixing rust-lang/cargo#14253
+    // Need to find a long-term solution to replace this fragile workaround.
+    // See https://github.com/rust-lang/cargo/pull/14432#discussion_r1725065350
+    if unit.kind.is_host() && !bcx.gctx.target_applies_to_host().unwrap_or_default() {
+        let host_info = bcx.target_data.info(CompileKind::Host);
+        let target_configs_are_different = unit.rustflags != host_info.rustflags
+            || unit.rustdocflags != host_info.rustdocflags
+            || bcx
+                .target_data
+                .target_config(CompileKind::Host)
+                .links_overrides
+                != unit.links_overrides;
+        target_configs_are_different.hash(&mut hasher);
+    }
+
     MetaInfo {
         meta_hash: Metadata(hasher.finish()),
         use_extra_filename: should_use_metadata(bcx, unit),


Test patch:
diff --git a/tests/testsuite/rustflags.rs b/tests/testsuite/rustflags.rs
index 81ce4c3ae..5d078b5be 100644
--- a/tests/testsuite/rustflags.rs
+++ b/tests/testsuite/rustflags.rs
@@ -1642,3 +1642,66 @@ fn target_applies_to_host_rustdocflags_works() {
         )
         .run();
 }
+
+#[cargo_test]
+fn host_config_shared_build_dep() {
+    // rust-lang/cargo#14253
+    Package::new("cc", "1.0.0").publish();
+    let p = project()
+        .file(
+            "Cargo.toml",
+            r#"
+            [package]
+            name = "bootstrap"
+            edition = "2021"
+
+            [dependencies]
+            cc = "1.0.0"
+
+            [build-dependencies]
+            cc = "1.0.0"
+
+            [profile.dev]
+            debug = 0
+            "#,
+        )
+        .file("src/lib.rs", "")
+        .file("build.rs", "fn main() {}")
+        .file(
+            ".cargo/config.toml",
+            "
+            target-applies-to-host=false
+
+            [host]
+            rustflags = ['--cfg', 'from_host']
+
+            [build]
+            rustflags = ['--cfg', 'from_target']
+            ",
+        )
+        .build();
+
+    p.cargo("build -v")
+        .masquerade_as_nightly_cargo(&["target-applies-to-host"])
+        .arg("-Ztarget-applies-to-host")
+        .arg("-Zhost-config")
+        .with_stderr_data(
+            str![[r#"
+[UPDATING] `dummy-registry` index
+[LOCKING] 2 packages to latest compatible versions
+[DOWNLOADING] crates ...
+[DOWNLOADED] cc v1.0.0 (registry `dummy-registry`)
+[COMPILING] cc v1.0.0
+[RUNNING] `rustc --crate-name cc [..]--cfg from_host[..]`
+[RUNNING] `rustc --crate-name cc [..]--cfg from_target[..]`
+[COMPILING] bootstrap v0.0.0 ([ROOT]/foo)
+[RUNNING] `rustc --crate-name build_script_build [..]--cfg from_host[..]`
+[RUNNING] `[ROOT]/foo/target/debug/build/bootstrap-[HASH]/build-script-build`
+[RUNNING] `rustc --crate-name bootstrap[..]--cfg from_target[..]`
+[FINISHED] `dev` profile [unoptimized] target(s) in [ELAPSED]s
+
+"#]]
+            .unordered(),
+        )
+        .run();
+}