/
dynlib.carp
74 lines (66 loc) · 2.28 KB
/
dynlib.carp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
(system-include "dlfcn.h")
(relative-include "dlfcn_helper.h")
(doc DynLib "DynLib is a module for loading shared libraries at runtime. It
strives to make code loading and calling dynamically easy.
```
(load \"https://github.com/carpentry-org/dynlib@0.0.4\")
(defn main []
(println*
&(=> (DynLib.open \"libt.so\")
(Maybe.to-result @\"Couldn’t open libt.so\")
(Result.and-then
(fn [lib] (Maybe.to-result (DynLib.get lib \"inc\")
@\"Couldn’t load symbol inc\")))
(Result.map (fn [f] (Int.str (f 1)))))))
```")
(defmodule DynLib
(register-type Lib)
(hidden lazy)
(register lazy Int "RTLD_LAZY")
(hidden now)
(register now Int "RTLD_NOW")
(hidden global)
(register global Int "RTLD_GLOBAL")
(hidden local)
(register local Int "RTLD_LOCAL")
(hidden dlopen)
(register dlopen (Fn [(Ptr CChar) Int] Lib) "dlopen")
(hidden dlsym)
(register dlsym (Fn [Lib (Ptr CChar)] (Ref a)) "DynLib_dlsym")
(hidden dlclose)
(register dlclose (Fn [Lib] Int) "dlclose")
(hidden dlerror)
(register dlerror (Fn [] String) "dlerror")
(hidden valid?)
(register valid? (Fn [a] Bool) "DynLib_isvalid")
(doc open "opens a shared library `lib`.")
(defn open [lib]
(let [l (dlopen (cstr lib) lazy)]
(if (valid? l)
(Maybe.Just l)
(Maybe.Nothing))))
(doc get "gets a function named `fname` from a shared library `lib`.")
(defn get [lib fname]
(let [f (dlsym lib (cstr fname))]
(if (valid? f)
(Maybe.Just @f)
(Maybe.Nothing))))
(doc get-from-module "gets a function named `fname` from a Carp module `md` from inside
a shared library `lib`.")
(defn get-from-module [lib md fname]
(let [fqn (fmt "%s_%s" &(Pattern.substitute #"\." md "_" -1) fname)
f (dlsym lib (cstr &fqn))]
(if (valid? f)
(Maybe.Just @f)
(Maybe.Nothing))))
(doc close "closes a library `lib`. Either returns nothing or, if an error
occurs, it returns the error message.")
(defn close [lib]
(if (= -1 (dlclose lib))
(Maybe.Just (dlerror))
(Maybe.Nothing)))
(defmacro rebind [lib s]
(list 'match (list 'DynLib.get lib (str s))
'(Maybe.Nothing) (list 'IO.errorln (String.join ["Failed to find symbol " (str s)]))
'(Maybe.Just s) (list set! s 's)))
)