3
3
mod version;
4
4
5
5
use proc_macro:: bridge;
6
- use std:: { fmt, fs:: File , io} ;
6
+ use std:: { fmt, fs, io, time :: SystemTime } ;
7
7
8
8
use libloading:: Library ;
9
9
use memmap2:: Mmap ;
10
10
use object:: Object ;
11
- use paths:: { AbsPath , Utf8Path , Utf8PathBuf } ;
11
+ use paths:: { Utf8Path , Utf8PathBuf } ;
12
12
use proc_macro_api:: ProcMacroKind ;
13
13
14
14
use crate :: ProcMacroSrvSpan ;
@@ -23,14 +23,9 @@ fn is_derive_registrar_symbol(symbol: &str) -> bool {
23
23
symbol. contains ( NEW_REGISTRAR_SYMBOL )
24
24
}
25
25
26
- fn find_registrar_symbol ( file : & Utf8Path ) -> io:: Result < Option < String > > {
27
- let file = File :: open ( file) ?;
28
- let buffer = unsafe { Mmap :: map ( & file) ? } ;
29
-
30
- Ok ( object:: File :: parse ( & * buffer)
31
- . map_err ( invalid_data_err) ?
32
- . exports ( )
33
- . map_err ( invalid_data_err) ?
26
+ fn find_registrar_symbol ( buffer : & [ u8 ] ) -> object:: Result < Option < String > > {
27
+ Ok ( object:: File :: parse ( buffer) ?
28
+ . exports ( ) ?
34
29
. into_iter ( )
35
30
. map ( |export| export. name ( ) )
36
31
. filter_map ( |sym| String :: from_utf8 ( sym. into ( ) ) . ok ( ) )
@@ -113,17 +108,17 @@ struct ProcMacroLibraryLibloading {
113
108
}
114
109
115
110
impl ProcMacroLibraryLibloading {
116
- fn open ( file : & Utf8Path ) -> Result < Self , LoadProcMacroDylibError > {
117
- let symbol_name = find_registrar_symbol ( file) ?. ok_or_else ( || {
118
- invalid_data_err ( format ! ( "Cannot find registrar symbol in file {file}" ) )
119
- } ) ?;
111
+ fn open ( path : & Utf8Path ) -> Result < Self , LoadProcMacroDylibError > {
112
+ let buffer = unsafe { Mmap :: map ( & fs:: File :: open ( path) ?) ? } ;
113
+ let symbol_name =
114
+ find_registrar_symbol ( & buffer) . map_err ( invalid_data_err) ?. ok_or_else ( || {
115
+ invalid_data_err ( format ! ( "Cannot find registrar symbol in file {path}" ) )
116
+ } ) ?;
120
117
121
- let abs_file: & AbsPath = file
122
- . try_into ( )
123
- . map_err ( |_| invalid_data_err ( format ! ( "expected an absolute path, got {file}" ) ) ) ?;
124
- let version_info = version:: read_dylib_info ( abs_file) ?;
118
+ let version_info = version:: read_dylib_info ( & buffer) ?;
119
+ drop ( buffer) ;
125
120
126
- let lib = load_library ( file ) . map_err ( invalid_data_err) ?;
121
+ let lib = load_library ( path ) . map_err ( invalid_data_err) ?;
127
122
let proc_macros = crate :: proc_macros:: ProcMacros :: from_lib (
128
123
& lib,
129
124
symbol_name,
@@ -133,30 +128,33 @@ impl ProcMacroLibraryLibloading {
133
128
}
134
129
}
135
130
136
- pub ( crate ) struct Expander {
137
- inner : ProcMacroLibraryLibloading ,
138
- path : Utf8PathBuf ,
139
- }
140
-
141
- impl Drop for Expander {
131
+ struct RemoveFileOnDrop ( Utf8PathBuf ) ;
132
+ impl Drop for RemoveFileOnDrop {
142
133
fn drop ( & mut self ) {
143
134
#[ cfg( windows) ]
144
- std:: fs:: remove_file ( & self . path ) . ok ( ) ;
145
- _ = self . path ;
135
+ std:: fs:: remove_file ( & self . 0 ) . unwrap ( ) ;
136
+ _ = self . 0 ;
146
137
}
147
138
}
148
139
140
+ // Drop order matters as we can't remove the dylib before the library is unloaded
141
+ pub ( crate ) struct Expander {
142
+ inner : ProcMacroLibraryLibloading ,
143
+ _remove_on_drop : RemoveFileOnDrop ,
144
+ modified_time : SystemTime ,
145
+ }
146
+
149
147
impl Expander {
150
148
pub ( crate ) fn new ( lib : & Utf8Path ) -> Result < Expander , LoadProcMacroDylibError > {
151
149
// Some libraries for dynamic loading require canonicalized path even when it is
152
150
// already absolute
153
151
let lib = lib. canonicalize_utf8 ( ) ?;
152
+ let modified_time = fs:: metadata ( & lib) . and_then ( |it| it. modified ( ) ) ?;
154
153
155
154
let path = ensure_file_with_lock_free_access ( & lib) ?;
156
-
157
155
let library = ProcMacroLibraryLibloading :: open ( path. as_ref ( ) ) ?;
158
156
159
- Ok ( Expander { inner : library, path } )
157
+ Ok ( Expander { inner : library, _remove_on_drop : RemoveFileOnDrop ( path) , modified_time } )
160
158
}
161
159
162
160
pub ( crate ) fn expand < S : ProcMacroSrvSpan > (
@@ -181,6 +179,10 @@ impl Expander {
181
179
pub ( crate ) fn list_macros ( & self ) -> Vec < ( String , ProcMacroKind ) > {
182
180
self . inner . proc_macros . list_macros ( )
183
181
}
182
+
183
+ pub ( crate ) fn modified_time ( & self ) -> SystemTime {
184
+ self . modified_time
185
+ }
184
186
}
185
187
186
188
/// Copy the dylib to temp directory to prevent locking in Windows
@@ -194,20 +196,23 @@ fn ensure_file_with_lock_free_access(path: &Utf8Path) -> io::Result<Utf8PathBuf>
194
196
}
195
197
196
198
let mut to = Utf8PathBuf :: from_path_buf ( std:: env:: temp_dir ( ) ) . unwrap ( ) ;
199
+ to. push ( "rust-analyzer-proc-macros" ) ;
200
+ _ = fs:: create_dir ( & to) ;
197
201
198
202
let file_name = path. file_name ( ) . ok_or_else ( || {
199
203
io:: Error :: new ( io:: ErrorKind :: InvalidInput , format ! ( "File path is invalid: {path}" ) )
200
204
} ) ?;
201
205
202
- // Generate a unique number by abusing `HashMap`'s hasher.
203
- // Maybe this will also "inspire" a libs team member to finally put `rand` in libstd.
204
- let t = RandomState :: new ( ) . build_hasher ( ) . finish ( ) ;
205
-
206
- let mut unique_name = t. to_string ( ) ;
207
- unique_name. push_str ( file_name) ;
208
-
209
- to. push ( unique_name) ;
210
- std:: fs:: copy ( path, & to) ?;
206
+ to. push ( {
207
+ // Generate a unique number by abusing `HashMap`'s hasher.
208
+ // Maybe this will also "inspire" a libs team member to finally put `rand` in libstd.
209
+ let t = RandomState :: new ( ) . build_hasher ( ) . finish ( ) ;
210
+ let mut unique_name = t. to_string ( ) ;
211
+ unique_name. push_str ( file_name) ;
212
+ unique_name. push ( '-' ) ;
213
+ unique_name
214
+ } ) ;
215
+ fs:: copy ( path, & to) ?;
211
216
Ok ( to)
212
217
}
213
218
0 commit comments