diff options
| author | Michael Woerister <michaelwoerister@posteo> | 2023-02-02 14:26:28 +0100 |
|---|---|---|
| committer | Michael Woerister <michaelwoerister@posteo> | 2023-02-02 16:18:16 +0100 |
| commit | 227b2858da8aac6791e86a86f938a652993e5ea3 (patch) | |
| tree | 91a9e92f41a9f10f05855d232874ebb41d825239 | |
| parent | a9985cf172e7cb8ab5c58ce2818752c3572754fc (diff) | |
| download | rust-227b2858da8aac6791e86a86f938a652993e5ea3.tar.gz rust-227b2858da8aac6791e86a86f938a652993e5ea3.zip | |
Retry opening proc-macro DLLs a few times on Windows.
| -rw-r--r-- | compiler/rustc_metadata/src/creader.rs | 42 |
1 files changed, 40 insertions, 2 deletions
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 653f2b39d3e..44d6c587da3 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -33,6 +33,7 @@ use rustc_target::spec::{PanicStrategy, TargetTriple}; use proc_macro::bridge::client::ProcMacro; use std::ops::Fn; use std::path::Path; +use std::time::Duration; use std::{cmp, env}; #[derive(Clone)] @@ -689,8 +690,7 @@ impl<'a> CrateLoader<'a> { ) -> Result<&'static [ProcMacro], CrateError> { // Make sure the path contains a / or the linker will search for it. let path = env::current_dir().unwrap().join(path); - let lib = unsafe { libloading::Library::new(path) } - .map_err(|err| CrateError::DlOpen(err.to_string()))?; + let lib = load_dylib(&path, 5).map_err(|err| CrateError::DlOpen(err))?; let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id); let sym = unsafe { lib.get::<*const &[ProcMacro]>(sym_name.as_bytes()) } @@ -1093,3 +1093,41 @@ fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> { visit::walk_crate(&mut f, krate); f.spans } + +// On Windows the compiler would sometimes intermittently fail to open the +// proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the +// system still holds a lock on the file, so we retry a few times before calling it +// an error. +fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, String> { + assert!(max_attempts > 0); + + let mut last_error = None; + + for attempt in 0..max_attempts { + match unsafe { libloading::Library::new(&path) } { + Ok(lib) => { + if attempt > 0 { + debug!( + "Loaded proc-macro `{}` after {} attempts.", + path.display(), + attempt + 1 + ); + } + return Ok(lib); + } + Err(err) => { + // Only try to recover from this specific error. + if !matches!(err, libloading::Error::LoadLibraryExW { .. }) { + return Err(err.to_string()); + } + + last_error = Some(err); + std::thread::sleep(Duration::from_millis(100)); + debug!("Failed to load proc-macro `{}`. Retrying.", path.display()); + } + } + } + + debug!("Failed to load proc-macro `{}` even after {} attempts.", path.display(), max_attempts); + Err(format!("{} (retried {} times)", last_error.unwrap(), max_attempts)) +} |
