diff options
Diffstat (limited to 'crates/ra_proc_macro_srv/src/dylib.rs')
-rw-r--r-- | crates/ra_proc_macro_srv/src/dylib.rs | 113 |
1 files changed, 69 insertions, 44 deletions
diff --git a/crates/ra_proc_macro_srv/src/dylib.rs b/crates/ra_proc_macro_srv/src/dylib.rs index d202eb0fd..aa84e951c 100644 --- a/crates/ra_proc_macro_srv/src/dylib.rs +++ b/crates/ra_proc_macro_srv/src/dylib.rs | |||
@@ -2,13 +2,12 @@ | |||
2 | 2 | ||
3 | use crate::{proc_macro::bridge, rustc_server::TokenStream}; | 3 | use crate::{proc_macro::bridge, rustc_server::TokenStream}; |
4 | use std::fs::File; | 4 | use std::fs::File; |
5 | use std::path::Path; | 5 | use std::path::{Path, PathBuf}; |
6 | 6 | ||
7 | use goblin::{mach::Mach, Object}; | 7 | use goblin::{mach::Mach, Object}; |
8 | use libloading::Library; | 8 | use libloading::Library; |
9 | use memmap::Mmap; | 9 | use memmap::Mmap; |
10 | use ra_proc_macro::ProcMacroKind; | 10 | use ra_proc_macro::ProcMacroKind; |
11 | |||
12 | use std::io; | 11 | use std::io; |
13 | 12 | ||
14 | const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_"; | 13 | const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_"; |
@@ -109,23 +108,21 @@ impl ProcMacroLibraryLibloading { | |||
109 | } | 108 | } |
110 | } | 109 | } |
111 | 110 | ||
112 | type ProcMacroLibraryImpl = ProcMacroLibraryLibloading; | ||
113 | |||
114 | pub struct Expander { | 111 | pub struct Expander { |
115 | libs: Vec<ProcMacroLibraryImpl>, | 112 | inner: ProcMacroLibraryLibloading, |
116 | } | 113 | } |
117 | 114 | ||
118 | impl Expander { | 115 | impl Expander { |
119 | pub fn new(lib: &Path) -> Result<Expander, String> { | 116 | pub fn new(lib: &Path) -> io::Result<Expander> { |
120 | // Some libraries for dynamic loading require canonicalized path even when it is | 117 | // Some libraries for dynamic loading require canonicalized path even when it is |
121 | // already absolute | 118 | // already absolute |
122 | let lib = lib | 119 | let lib = lib.canonicalize()?; |
123 | .canonicalize() | 120 | |
124 | .unwrap_or_else(|err| panic!("Cannot canonicalize {}: {:?}", lib.display(), err)); | 121 | let lib = ensure_file_with_lock_free_access(&lib)?; |
125 | 122 | ||
126 | let library = ProcMacroLibraryImpl::open(&lib).map_err(|e| e.to_string())?; | 123 | let library = ProcMacroLibraryLibloading::open(&lib)?; |
127 | 124 | ||
128 | Ok(Expander { libs: vec![library] }) | 125 | Ok(Expander { inner: library }) |
129 | } | 126 | } |
130 | 127 | ||
131 | pub fn expand( | 128 | pub fn expand( |
@@ -141,38 +138,36 @@ impl Expander { | |||
141 | TokenStream::with_subtree(attr.clone()) | 138 | TokenStream::with_subtree(attr.clone()) |
142 | }); | 139 | }); |
143 | 140 | ||
144 | for lib in &self.libs { | 141 | for proc_macro in &self.inner.exported_macros { |
145 | for proc_macro in &lib.exported_macros { | 142 | match proc_macro { |
146 | match proc_macro { | 143 | bridge::client::ProcMacro::CustomDerive { trait_name, client, .. } |
147 | bridge::client::ProcMacro::CustomDerive { trait_name, client, .. } | 144 | if *trait_name == macro_name => |
148 | if *trait_name == macro_name => | 145 | { |
149 | { | 146 | let res = client.run( |
150 | let res = client.run( | 147 | &crate::proc_macro::bridge::server::SameThread, |
151 | &crate::proc_macro::bridge::server::SameThread, | 148 | crate::rustc_server::Rustc::default(), |
152 | crate::rustc_server::Rustc::default(), | 149 | parsed_body, |
153 | parsed_body, | 150 | ); |
154 | ); | 151 | return res.map(|it| it.subtree); |
155 | return res.map(|it| it.subtree); | 152 | } |
156 | } | 153 | bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { |
157 | bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { | 154 | let res = client.run( |
158 | let res = client.run( | 155 | &crate::proc_macro::bridge::server::SameThread, |
159 | &crate::proc_macro::bridge::server::SameThread, | 156 | crate::rustc_server::Rustc::default(), |
160 | crate::rustc_server::Rustc::default(), | 157 | parsed_body, |
161 | parsed_body, | 158 | ); |
162 | ); | 159 | return res.map(|it| it.subtree); |
163 | return res.map(|it| it.subtree); | 160 | } |
164 | } | 161 | bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { |
165 | bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { | 162 | let res = client.run( |
166 | let res = client.run( | 163 | &crate::proc_macro::bridge::server::SameThread, |
167 | &crate::proc_macro::bridge::server::SameThread, | 164 | crate::rustc_server::Rustc::default(), |
168 | crate::rustc_server::Rustc::default(), | 165 | parsed_attributes, |
169 | parsed_attributes, | 166 | parsed_body, |
170 | parsed_body, | 167 | ); |
171 | ); | 168 | return res.map(|it| it.subtree); |
172 | return res.map(|it| it.subtree); | ||
173 | } | ||
174 | _ => continue, | ||
175 | } | 169 | } |
170 | _ => continue, | ||
176 | } | 171 | } |
177 | } | 172 | } |
178 | 173 | ||
@@ -180,9 +175,9 @@ impl Expander { | |||
180 | } | 175 | } |
181 | 176 | ||
182 | pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { | 177 | pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { |
183 | self.libs | 178 | self.inner |
179 | .exported_macros | ||
184 | .iter() | 180 | .iter() |
185 | .flat_map(|it| &it.exported_macros) | ||
186 | .map(|proc_macro| match proc_macro { | 181 | .map(|proc_macro| match proc_macro { |
187 | bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { | 182 | bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { |
188 | (trait_name.to_string(), ProcMacroKind::CustomDerive) | 183 | (trait_name.to_string(), ProcMacroKind::CustomDerive) |
@@ -197,3 +192,33 @@ impl Expander { | |||
197 | .collect() | 192 | .collect() |
198 | } | 193 | } |
199 | } | 194 | } |
195 | |||
196 | /// Copy the dylib to temp directory to prevent locking in Windows | ||
197 | #[cfg(windows)] | ||
198 | fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> { | ||
199 | use std::{ffi::OsString, time::SystemTime}; | ||
200 | |||
201 | let mut to = std::env::temp_dir(); | ||
202 | |||
203 | let file_name = path.file_name().ok_or_else(|| { | ||
204 | io::Error::new( | ||
205 | io::ErrorKind::InvalidInput, | ||
206 | format!("File path is invalid: {}", path.display()), | ||
207 | ) | ||
208 | })?; | ||
209 | |||
210 | // generate a time deps unique number | ||
211 | let t = SystemTime::now().duration_since(std::time::UNIX_EPOCH).expect("Time went backwards"); | ||
212 | |||
213 | let mut unique_name = OsString::from(t.as_millis().to_string()); | ||
214 | unique_name.push(file_name); | ||
215 | |||
216 | to.push(unique_name); | ||
217 | std::fs::copy(path, &to).unwrap(); | ||
218 | Ok(to) | ||
219 | } | ||
220 | |||
221 | #[cfg(unix)] | ||
222 | fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> { | ||
223 | Ok(path.to_path_buf()) | ||
224 | } | ||