11//! Handles dynamic library loading for proc macro
22
3+ mod proc_macros;
34mod version;
45
56use proc_macro:: bridge;
@@ -10,57 +11,56 @@ use libloading::Library;
1011use object:: Object ;
1112use paths:: { Utf8Path , Utf8PathBuf } ;
1213
13- use crate :: { ProcMacroKind , ProcMacroSrvSpan , proc_macros:: ProcMacros , server_impl:: TopSubtree } ;
14+ use crate :: {
15+ PanicMessage , ProcMacroKind , ProcMacroSrvSpan , dylib:: proc_macros:: ProcMacros ,
16+ server_impl:: TopSubtree ,
17+ } ;
1418
15- /// Loads dynamic library in platform dependent manner.
16- ///
17- /// For unix, you have to use RTLD_DEEPBIND flag to escape problems described
18- /// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample)
19- /// and [here](https://github.com/rust-lang/rust/issues/60593).
20- ///
21- /// Usage of RTLD_DEEPBIND
22- /// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1)
23- ///
24- /// It seems that on Windows that behaviour is default, so we do nothing in that case.
25- ///
26- /// # Safety
27- ///
28- /// The caller is responsible for ensuring that the path is valid proc-macro library
29- #[ cfg( windows) ]
30- unsafe fn load_library ( file : & Utf8Path ) -> Result < Library , libloading:: Error > {
31- // SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library
32- unsafe { Library :: new ( file) }
19+ pub ( crate ) struct Expander {
20+ inner : ProcMacroLibrary ,
21+ modified_time : SystemTime ,
3322}
3423
35- /// Loads dynamic library in platform dependent manner.
36- ///
37- /// For unix, you have to use RTLD_DEEPBIND flag to escape problems described
38- /// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample)
39- /// and [here](https://github.com/rust-lang/rust/issues/60593).
40- ///
41- /// Usage of RTLD_DEEPBIND
42- /// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1)
43- ///
44- /// It seems that on Windows that behaviour is default, so we do nothing in that case.
45- ///
46- /// # Safety
47- ///
48- /// The caller is responsible for ensuring that the path is valid proc-macro library
49- #[ cfg( unix) ]
50- unsafe fn load_library ( file : & Utf8Path ) -> Result < Library , libloading:: Error > {
51- // not defined by POSIX, different values on mips vs other targets
52- #[ cfg( target_env = "gnu" ) ]
53- use libc:: RTLD_DEEPBIND ;
54- use libloading:: os:: unix:: Library as UnixLibrary ;
55- // defined by POSIX
56- use libloading:: os:: unix:: RTLD_NOW ;
24+ impl Expander {
25+ pub ( crate ) fn new (
26+ temp_dir : & TempDir ,
27+ lib : & Utf8Path ,
28+ ) -> Result < Expander , LoadProcMacroDylibError > {
29+ // Some libraries for dynamic loading require canonicalized path even when it is
30+ // already absolute
31+ let lib = lib. canonicalize_utf8 ( ) ?;
32+ let modified_time = fs:: metadata ( & lib) . and_then ( |it| it. modified ( ) ) ?;
5733
58- // MUSL and bionic don't have it..
59- #[ cfg( not( target_env = "gnu" ) ) ]
60- const RTLD_DEEPBIND : std:: os:: raw:: c_int = 0x0 ;
34+ let path = ensure_file_with_lock_free_access ( temp_dir, & lib) ?;
35+ let library = ProcMacroLibrary :: open ( path. as_ref ( ) ) ?;
6136
62- // SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library
63- unsafe { UnixLibrary :: open ( Some ( file) , RTLD_NOW | RTLD_DEEPBIND ) . map ( |lib| lib. into ( ) ) }
37+ Ok ( Expander { inner : library, modified_time } )
38+ }
39+
40+ pub ( crate ) fn expand < S : ProcMacroSrvSpan > (
41+ & self ,
42+ macro_name : & str ,
43+ macro_body : TopSubtree < S > ,
44+ attributes : Option < TopSubtree < S > > ,
45+ def_site : S ,
46+ call_site : S ,
47+ mixed_site : S ,
48+ ) -> Result < TopSubtree < S > , PanicMessage >
49+ where
50+ <S :: Server as bridge:: server:: Types >:: TokenStream : Default ,
51+ {
52+ self . inner
53+ . proc_macros
54+ . expand ( macro_name, macro_body, attributes, def_site, call_site, mixed_site)
55+ }
56+
57+ pub ( crate ) fn list_macros ( & self ) -> impl Iterator < Item = ( & str , ProcMacroKind ) > {
58+ self . inner . proc_macros . list_macros ( )
59+ }
60+
61+ pub ( crate ) fn modified_time ( & self ) -> SystemTime {
62+ self . modified_time
63+ }
6464}
6565
6666#[ derive( Debug ) ]
@@ -134,57 +134,6 @@ impl ProcMacroLibrary {
134134 }
135135}
136136
137- // Drop order matters as we can't remove the dylib before the library is unloaded
138- pub ( crate ) struct Expander {
139- inner : ProcMacroLibrary ,
140- _remove_on_drop : RemoveFileOnDrop ,
141- modified_time : SystemTime ,
142- }
143-
144- impl Expander {
145- pub ( crate ) fn new (
146- temp_dir : & TempDir ,
147- lib : & Utf8Path ,
148- ) -> Result < Expander , LoadProcMacroDylibError > {
149- // Some libraries for dynamic loading require canonicalized path even when it is
150- // already absolute
151- let lib = lib. canonicalize_utf8 ( ) ?;
152- let modified_time = fs:: metadata ( & lib) . and_then ( |it| it. modified ( ) ) ?;
153-
154- let path = ensure_file_with_lock_free_access ( temp_dir, & lib) ?;
155- let library = ProcMacroLibrary :: open ( path. as_ref ( ) ) ?;
156-
157- Ok ( Expander { inner : library, _remove_on_drop : RemoveFileOnDrop ( path) , modified_time } )
158- }
159-
160- pub ( crate ) fn expand < S : ProcMacroSrvSpan > (
161- & self ,
162- macro_name : & str ,
163- macro_body : TopSubtree < S > ,
164- attributes : Option < TopSubtree < S > > ,
165- def_site : S ,
166- call_site : S ,
167- mixed_site : S ,
168- ) -> Result < TopSubtree < S > , String >
169- where
170- <S :: Server as bridge:: server:: Types >:: TokenStream : Default ,
171- {
172- let result = self
173- . inner
174- . proc_macros
175- . expand ( macro_name, macro_body, attributes, def_site, call_site, mixed_site) ;
176- result. map_err ( |e| e. into_string ( ) . unwrap_or_default ( ) )
177- }
178-
179- pub ( crate ) fn list_macros ( & self ) -> Vec < ( String , ProcMacroKind ) > {
180- self . inner . proc_macros . list_macros ( )
181- }
182-
183- pub ( crate ) fn modified_time ( & self ) -> SystemTime {
184- self . modified_time
185- }
186- }
187-
188137fn invalid_data_err ( e : impl Into < Box < dyn std:: error:: Error + Send + Sync > > ) -> io:: Error {
189138 io:: Error :: new ( io:: ErrorKind :: InvalidData , e)
190139}
@@ -214,15 +163,6 @@ fn find_registrar_symbol(obj: &object::File<'_>) -> object::Result<Option<String
214163 } ) )
215164}
216165
217- struct RemoveFileOnDrop ( Utf8PathBuf ) ;
218- impl Drop for RemoveFileOnDrop {
219- fn drop ( & mut self ) {
220- #[ cfg( windows) ]
221- std:: fs:: remove_file ( & self . 0 ) . unwrap ( ) ;
222- _ = self . 0 ;
223- }
224- }
225-
226166/// Copy the dylib to temp directory to prevent locking in Windows
227167#[ cfg( windows) ]
228168fn ensure_file_with_lock_free_access (
@@ -259,3 +199,54 @@ fn ensure_file_with_lock_free_access(
259199) -> io:: Result < Utf8PathBuf > {
260200 Ok ( path. to_owned ( ) )
261201}
202+
203+ /// Loads dynamic library in platform dependent manner.
204+ ///
205+ /// For unix, you have to use RTLD_DEEPBIND flag to escape problems described
206+ /// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample)
207+ /// and [here](https://github.com/rust-lang/rust/issues/60593).
208+ ///
209+ /// Usage of RTLD_DEEPBIND
210+ /// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1)
211+ ///
212+ /// It seems that on Windows that behaviour is default, so we do nothing in that case.
213+ ///
214+ /// # Safety
215+ ///
216+ /// The caller is responsible for ensuring that the path is valid proc-macro library
217+ #[ cfg( windows) ]
218+ unsafe fn load_library ( file : & Utf8Path ) -> Result < Library , libloading:: Error > {
219+ // SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library
220+ unsafe { Library :: new ( file) }
221+ }
222+
223+ /// Loads dynamic library in platform dependent manner.
224+ ///
225+ /// For unix, you have to use RTLD_DEEPBIND flag to escape problems described
226+ /// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample)
227+ /// and [here](https://github.com/rust-lang/rust/issues/60593).
228+ ///
229+ /// Usage of RTLD_DEEPBIND
230+ /// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1)
231+ ///
232+ /// It seems that on Windows that behaviour is default, so we do nothing in that case.
233+ ///
234+ /// # Safety
235+ ///
236+ /// The caller is responsible for ensuring that the path is valid proc-macro library
237+ #[ cfg( unix) ]
238+ unsafe fn load_library ( file : & Utf8Path ) -> Result < Library , libloading:: Error > {
239+ // not defined by POSIX, different values on mips vs other targets
240+ #[ cfg( target_env = "gnu" ) ]
241+ use libc:: RTLD_DEEPBIND ;
242+ use libloading:: os:: unix:: Library as UnixLibrary ;
243+ // defined by POSIX
244+ use libloading:: os:: unix:: RTLD_NOW ;
245+
246+ // MUSL and bionic don't have it..
247+ #[ cfg( not( target_env = "gnu" ) ) ]
248+ const RTLD_DEEPBIND : std:: os:: raw:: c_int = 0x0 ;
249+
250+ // SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library
251+ unsafe { UnixLibrary :: open ( Some ( file) , RTLD_NOW | RTLD_DEEPBIND ) . map ( |lib| lib. into ( ) ) }
252+ }
0 commit comments