22
33use crate :: { proc_macro:: bridge, rustc_server:: TokenStream } ;
44use std:: fs:: File ;
5- use std:: path:: Path ;
5+ use std:: path:: { Path , PathBuf } ;
66
77use goblin:: { mach:: Mach , Object } ;
88use libloading:: Library ;
99use memmap:: Mmap ;
1010use ra_proc_macro:: ProcMacroKind ;
11-
1211use std:: io;
1312
1413const NEW_REGISTRAR_SYMBOL : & str = "_rustc_proc_macro_decls_" ;
@@ -109,23 +108,21 @@ impl ProcMacroLibraryLibloading {
109108 }
110109}
111110
112- type ProcMacroLibraryImpl = ProcMacroLibraryLibloading ;
113-
114111pub struct Expander {
115- libs : Vec < ProcMacroLibraryImpl > ,
112+ inner : ProcMacroLibraryLibloading ,
116113}
117114
118115impl Expander {
119- pub fn new ( lib : & Path ) -> Result < Expander , String > {
116+ pub fn new ( lib : & Path ) -> io :: Result < Expander > {
120117 // Some libraries for dynamic loading require canonicalized path even when it is
121118 // already absolute
122- let lib = lib
123- . canonicalize ( )
124- . unwrap_or_else ( |err| panic ! ( "Cannot canonicalize {}: {:?}" , lib. display ( ) , err ) ) ;
119+ let lib = lib. canonicalize ( ) ? ;
120+
121+ let lib = ensure_file_with_lock_free_access ( & lib) ? ;
125122
126- let library = ProcMacroLibraryImpl :: open ( & lib) . map_err ( |e| e . to_string ( ) ) ?;
123+ let library = ProcMacroLibraryLibloading :: open ( & lib) ?;
127124
128- Ok ( Expander { libs : vec ! [ library] } )
125+ Ok ( Expander { inner : library } )
129126 }
130127
131128 pub fn expand (
@@ -141,48 +138,46 @@ impl Expander {
141138 TokenStream :: with_subtree ( attr. clone ( ) )
142139 } ) ;
143140
144- for lib in & self . libs {
145- for proc_macro in & lib. exported_macros {
146- match proc_macro {
147- bridge:: client:: ProcMacro :: CustomDerive { trait_name, client, .. }
148- if * trait_name == macro_name =>
149- {
150- let res = client. run (
151- & crate :: proc_macro:: bridge:: server:: SameThread ,
152- crate :: rustc_server:: Rustc :: default ( ) ,
153- parsed_body,
154- ) ;
155- return res. map ( |it| it. subtree ) ;
156- }
157- bridge:: client:: ProcMacro :: Bang { name, client } if * name == macro_name => {
158- let res = client. run (
159- & crate :: proc_macro:: bridge:: server:: SameThread ,
160- crate :: rustc_server:: Rustc :: default ( ) ,
161- parsed_body,
162- ) ;
163- return res. map ( |it| it. subtree ) ;
164- }
165- bridge:: client:: ProcMacro :: Attr { name, client } if * name == macro_name => {
166- let res = client. run (
167- & crate :: proc_macro:: bridge:: server:: SameThread ,
168- crate :: rustc_server:: Rustc :: default ( ) ,
169- parsed_attributes,
170- parsed_body,
171- ) ;
172- return res. map ( |it| it. subtree ) ;
173- }
174- _ => continue ,
141+ for proc_macro in & self . inner . exported_macros {
142+ match proc_macro {
143+ bridge:: client:: ProcMacro :: CustomDerive { trait_name, client, .. }
144+ if * trait_name == macro_name =>
145+ {
146+ let res = client. run (
147+ & crate :: proc_macro:: bridge:: server:: SameThread ,
148+ crate :: rustc_server:: Rustc :: default ( ) ,
149+ parsed_body,
150+ ) ;
151+ return res. map ( |it| it. subtree ) ;
152+ }
153+ bridge:: client:: ProcMacro :: Bang { name, client } if * name == macro_name => {
154+ let res = client. run (
155+ & crate :: proc_macro:: bridge:: server:: SameThread ,
156+ crate :: rustc_server:: Rustc :: default ( ) ,
157+ parsed_body,
158+ ) ;
159+ return res. map ( |it| it. subtree ) ;
160+ }
161+ bridge:: client:: ProcMacro :: Attr { name, client } if * name == macro_name => {
162+ let res = client. run (
163+ & crate :: proc_macro:: bridge:: server:: SameThread ,
164+ crate :: rustc_server:: Rustc :: default ( ) ,
165+ parsed_attributes,
166+ parsed_body,
167+ ) ;
168+ return res. map ( |it| it. subtree ) ;
175169 }
170+ _ => continue ,
176171 }
177172 }
178173
179174 Err ( bridge:: PanicMessage :: String ( "Nothing to expand" . to_string ( ) ) )
180175 }
181176
182177 pub fn list_macros ( & self ) -> Vec < ( String , ProcMacroKind ) > {
183- self . libs
178+ self . inner
179+ . exported_macros
184180 . iter ( )
185- . flat_map ( |it| & it. exported_macros )
186181 . map ( |proc_macro| match proc_macro {
187182 bridge:: client:: ProcMacro :: CustomDerive { trait_name, .. } => {
188183 ( trait_name. to_string ( ) , ProcMacroKind :: CustomDerive )
@@ -197,3 +192,33 @@ impl Expander {
197192 . collect ( )
198193 }
199194}
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+ }
0 commit comments