]> git.lizzy.rs Git - rust.git/blob - src/libstd/unstable/dynamic_lib.rs
auto merge of #7096 : huonw/rust/invalid-null-str, r=thestinger
[rust.git] / src / libstd / unstable / dynamic_lib.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12
13 Dynamic library facilities.
14
15 A simple wrapper over the platforms dynamic library facilities
16
17 */
18 use ptr;
19 use cast;
20 use path;
21 use libc;
22 use ops::*;
23 use option::*;
24 use result::*;
25
26 pub struct DynamicLibrary { priv handle: *libc::c_void }
27
28 impl Drop for DynamicLibrary {
29     fn finalize(&self) {
30         match do dl::check_for_errors_in {
31             unsafe {
32                 dl::close(self.handle)
33             }
34         } {
35             Ok(()) => { },
36             Err(str) => fail!(str)
37         }
38     }
39 }
40
41 impl DynamicLibrary {
42     /// Lazily open a dynamic library. When passed None it gives a
43     /// handle to the calling process
44     pub fn open(filename: Option<&path::Path>) -> Result<DynamicLibrary, ~str> {
45         let open_wrapper = |raw_ptr| {
46             do dl::check_for_errors_in {
47                 unsafe {
48                     DynamicLibrary { handle: dl::open(raw_ptr) }
49                 }
50             }
51         };
52
53         match filename {
54             Some(name) => do name.to_str().as_c_str |raw_name| {
55                 open_wrapper(raw_name)
56             },
57             None => open_wrapper(ptr::null())
58         }
59     }
60
61     /// Access the value at the symbol of the dynamic library
62     pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<T, ~str> {
63         // This function should have a lifetime constraint of 'self on
64         // T but that feature is still unimplemented
65
66         do dl::check_for_errors_in {
67             let symbol_value = do symbol.as_c_str |raw_string| {
68                 dl::symbol(self.handle, raw_string)
69             };
70
71             cast::transmute(symbol_value)
72         }
73     }
74 }
75
76 #[test]
77 priv fn test_loading_cosine () {
78     // The math library does not need to be loaded since it is already
79     // statically linked in
80     let libm = match DynamicLibrary::open(None) {
81         Err (error) => fail!("Could not load self as module: %s", error),
82         Ok (libm) => libm
83     };
84
85     // Unfortunately due to issue #6194 it is not possible to call
86     // this as a C function
87     let cosine: extern fn(libc::c_double) -> libc::c_double = unsafe {
88         match libm.symbol("cos") {
89             Err (error) => fail!("Could not load function cos: %s", error),
90             Ok (cosine) => cosine
91         }
92     };
93
94     let argument = 0.0;
95     let expected_result = 1.0;
96     let result = cosine(argument);
97     if result != expected_result {
98         fail!("cos(%?) != %? but equaled %? instead", argument,
99               expected_result, result)
100     }
101 }
102
103 #[cfg(target_os = "linux")]
104 #[cfg(target_os = "android")]
105 #[cfg(target_os = "macos")]
106 #[cfg(target_os = "freebsd")]
107 mod dl {
108     use libc;
109     use ptr;
110     use str;
111     use task;
112     use result::*;
113
114     pub unsafe fn open(filename: *libc::c_char) -> *libc::c_void {
115         dlopen(filename, Lazy as libc::c_int)
116     }
117
118     pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
119         unsafe {
120             do task::atomically {
121                 let _old_error = dlerror();
122
123                 let result = f();
124
125                 let last_error = dlerror();
126                 if ptr::null() == last_error {
127                     Ok(result)
128                 } else {
129                     Err(str::raw::from_c_str(last_error))
130                 }
131             }
132         }
133     }
134
135     pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
136         dlsym(handle, symbol)
137     }
138     pub unsafe fn close(handle: *libc::c_void) {
139         dlclose(handle); ()
140     }
141
142     pub enum RTLD {
143         Lazy = 1,
144         Now = 2,
145         Global = 256,
146         Local = 0,
147     }
148
149     #[link_name = "dl"]
150     extern {
151         fn dlopen(filename: *libc::c_char, flag: libc::c_int) -> *libc::c_void;
152         fn dlerror() -> *libc::c_char;
153         fn dlsym(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void;
154         fn dlclose(handle: *libc::c_void) -> libc::c_int;
155     }
156 }
157
158 #[cfg(target_os = "win32")]
159 mod dl {
160     use os;
161     use libc;
162     use task;
163     use result::*;
164
165     pub unsafe fn open(filename: *libc::c_char) -> *libc::c_void {
166         LoadLibrary(filename)
167     }
168
169     pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
170         unsafe {
171             do task::atomically {
172                 SetLastError(0);
173
174                 let result = f();
175
176                 let error = os::errno();
177                 if 0 == error {
178                     Ok(result)
179                 } else {
180                     Err(fmt!("Error code %?", error))
181                 }
182             }
183         }
184     }
185     pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
186         GetProcAddress(handle, symbol)
187     }
188     pub unsafe fn close(handle: *libc::c_void) {
189         FreeLibrary(handle); ()
190     }
191
192     #[link_name = "kernel32"]
193     extern "stdcall" {
194         fn SetLastError(error: u32);
195         fn LoadLibrary(name: *libc::c_char) -> *libc::c_void;
196         fn GetProcAddress(handle: *libc::c_void, name: *libc::c_char) -> *libc::c_void;
197         fn FreeLibrary(handle: *libc::c_void);
198     }
199 }