Skip to content

Commit 6c45160

Browse files
committed
auto merge of #7027 : sstewartgallus/rust/dynamic_lib, r=graydon
I would appreciate if someone could help out with the Windows code on this pull request. I tried to test it using WINE but I couldn't figure out a way to set that up.
2 parents da510bf + 786ea3f commit 6c45160

File tree

2 files changed

+207
-0
lines changed

2 files changed

+207
-0
lines changed

src/libstd/unstable/dynamic_lib.rs

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
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+
}

src/libstd/unstable/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ use prelude::*;
1717
use task;
1818

1919
pub mod at_exit;
20+
21+
// Currently only works for *NIXes
22+
#[cfg(target_os = "linux")]
23+
#[cfg(target_os = "android")]
24+
#[cfg(target_os = "macos")]
25+
#[cfg(target_os = "freebsd")]
26+
pub mod dynamic_lib;
27+
2028
pub mod global;
2129
pub mod finally;
2230
pub mod weak_task;

0 commit comments

Comments
 (0)