Repository: dtolnay/cxx (language: rust)

Issue:
cxxbridge error: Failed to create symlink
Seeing the following intermittent build failure in our pipeline builds.  Ubuntu 20 based container.  It occasionally fails.

```
cxxbridge error: Failed to create symlink `/builds/-F39GCyv/2/.../target/cxxbridge/rust/cxx.h` pointing to `/builds/-F39GCyv/2/.../.cargo/registry/src/github.com-1ecc6299db9ec823/cxx-1.0.49/include/cxx.h`

 Caused by:

File exists (os error 17)
```

Could be file is not synchronized to disk, and the create symlink call is reading through to disk?


Discussion / hints:

Fix patch:
diff --git a/gen/build/src/out.rs b/gen/build/src/out.rs
index e275049c6..5fe957c97 100644
--- a/gen/build/src/out.rs
+++ b/gen/build/src/out.rs
@@ -1,6 +1,7 @@
 use crate::error::{Error, Result};
 use crate::gen::fs;
 use crate::paths;
+use std::io;
 use std::path::Path;
 
 pub(crate) fn write(path: impl AsRef<Path>, content: &[u8]) -> Result<()> {
@@ -43,8 +44,22 @@ pub(crate) fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -
     match paths::symlink_or_copy(original, link) {
         // As long as symlink_or_copy succeeded, ignore any create_dir_all error.
         Ok(()) => Ok(()),
-        // If create_dir_all and symlink_or_copy both failed, prefer the first error.
-        Err(err) => Err(Error::Fs(create_dir_error.unwrap_or(err))),
+        Err(err) => {
+            if err.kind() == io::ErrorKind::AlreadyExists {
+                // This is fine, a different simultaneous build script already
+                // created the same link or copy. The cxx_build target directory
+                // is laid out such that the same path never refers to two
+                // different targets during the same multi-crate build, so if
+                // some other build script already created the same path then we
+                // know it refers to the identical target that the current build
+                // script was trying to create.
+                Ok(())
+            } else {
+                // If create_dir_all and symlink_or_copy both failed, prefer the
+                // first error.
+                Err(Error::Fs(create_dir_error.unwrap_or(err)))
+            }
+        }
     }
 }
 
diff --git a/gen/src/fs.rs b/gen/src/fs.rs
index 7053cc447..bfda58294 100644
--- a/gen/src/fs.rs
+++ b/gen/src/fs.rs
@@ -13,6 +13,15 @@ pub(crate) struct Error {
     message: String,
 }
 
+impl Error {
+    pub fn kind(&self) -> io::ErrorKind {
+        match &self.source {
+            Some(io_error) => io_error.kind(),
+            None => io::ErrorKind::Other,
+        }
+    }
+}
+
 impl Display for Error {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         formatter.write_str(&self.message)


Test patch: