Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | signature DYN_LINK = |
2 | sig | |
3 | type hndl | |
4 | type mode | |
5 | type fptr | |
6 | ||
7 | val dlopen : string * mode -> hndl | |
8 | val dlsym : hndl * string -> fptr | |
9 | val dlclose : hndl -> unit | |
10 | ||
11 | val RTLD_LAZY : mode | |
12 | val RTLD_NOW : mode | |
13 | end | |
14 | ||
15 | structure DynLink :> DYN_LINK = | |
16 | struct | |
17 | type hndl = MLton.Pointer.t | |
18 | type mode = Word32.word | |
19 | type fptr = MLton.Pointer.t | |
20 | ||
21 | (* These symbols come from a system libray, so the default import scope | |
22 | * of external is correct. | |
23 | *) | |
24 | val dlopen = | |
25 | _import "dlopen" : string * mode -> hndl; | |
26 | val dlerror = | |
27 | _import "dlerror": unit -> MLton.Pointer.t; | |
28 | val dlsym = | |
29 | _import "dlsym" : hndl * string -> fptr; | |
30 | val dlclose = | |
31 | _import "dlclose" : hndl -> Int32.int; | |
32 | ||
33 | val RTLD_LAZY = 0wx00001 (* Lazy function call binding. *) | |
34 | val RTLD_NOW = 0wx00002 (* Immediate function call binding. *) | |
35 | ||
36 | val dlerror = fn () => | |
37 | let | |
38 | val addr = dlerror () | |
39 | in | |
40 | if addr = MLton.Pointer.null | |
41 | then NONE | |
42 | else let | |
43 | fun loop (index, cs) = | |
44 | let | |
45 | val w = MLton.Pointer.getWord8 (addr, index) | |
46 | val c = Byte.byteToChar w | |
47 | in | |
48 | if c = #"\000" | |
49 | then SOME (implode (rev cs)) | |
50 | else loop (index + 1, c::cs) | |
51 | end | |
52 | in | |
53 | loop (0, []) | |
54 | end | |
55 | end | |
56 | ||
57 | val dlopen = fn (filename, mode) => | |
58 | let | |
59 | val filename = filename ^ "\000" | |
60 | val hndl = dlopen (filename, mode) | |
61 | in | |
62 | if hndl = MLton.Pointer.null | |
63 | then raise Fail (case dlerror () of | |
64 | NONE => "???" | |
65 | | SOME s => s) | |
66 | else hndl | |
67 | end | |
68 | ||
69 | val dlsym = fn (hndl, symbol) => | |
70 | let | |
71 | val symbol = symbol ^ "\000" | |
72 | val fptr = dlsym (hndl, symbol) | |
73 | in | |
74 | case dlerror () of | |
75 | NONE => fptr | |
76 | | SOME s => raise Fail s | |
77 | end | |
78 | ||
79 | val dlclose = fn hndl => | |
80 | if MLton.Platform.OS.host = MLton.Platform.OS.Darwin | |
81 | then () (* Darwin reports the following error message if you | |
82 | * try to close a dynamic library. | |
83 | * "dynamic libraries cannot be closed" | |
84 | * So, we disable dlclose on Darwin. | |
85 | *) | |
86 | else | |
87 | let | |
88 | val res = dlclose hndl | |
89 | in | |
90 | if res = 0 | |
91 | then () | |
92 | else raise Fail (case dlerror () of | |
93 | NONE => "???" | |
94 | | SOME s => s) | |
95 | end | |
96 | end | |
97 | ||
98 | val dll = | |
99 | let | |
100 | open MLton.Platform.OS | |
101 | in | |
102 | case host of | |
103 | Cygwin => "cygwin1.dll" | |
104 | | Darwin => "libm.dylib" | |
105 | | _ => "libm.so" | |
106 | end | |
107 | ||
108 | val hndl = DynLink.dlopen (dll, DynLink.RTLD_LAZY) | |
109 | ||
110 | local | |
111 | val double_to_double = | |
112 | _import * : DynLink.fptr -> real -> real; | |
113 | val cos_fptr = DynLink.dlsym (hndl, "cos") | |
114 | in | |
115 | val cos = double_to_double cos_fptr | |
116 | end | |
117 | ||
118 | val _ = print (concat [" Math.cos(2.0) = ", Real.toString (Math.cos 2.0), "\n", | |
119 | "libm.so::cos(2.0) = ", Real.toString (cos 2.0), "\n"]) | |
120 | ||
121 | val _ = DynLink.dlclose hndl |