Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,28 @@ Provided there is a function `inc` that increments a number in a library
follows:

```clojure
(load "https://github.com/carpentry-org/dynlib@0.0.4")
(load "https://github.com/carpentry-org/dynlib@0.0.5")

(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")))
(fn [lib] (DynLib.get lib "inc")))
(Result.map (fn [f] (Int.str (f 1)))))))
```

We’re using `Result` here to get informative error messages, but this is all
optional. If you want to throw safety out of the window, something like this
could also work—though I wholeheartedly advise against it:
`open` and `get` return `(Result a String)`, so the error branch already
carries the real `dlerror()` message—no need to wrap in `Maybe.to-result`.

If you want to throw safety out of the window, something like this could also
work—though I wholeheartedly advise against it:

```clojure
(load "https://github.com/carpentry-org/dynlib@0.0.3")
(load "https://github.com/carpentry-org/dynlib@0.0.5")

(defn main []
(let [lib (Maybe.unsafe-from (DynLib.open "libt.so"))
f (Maybe.unsafe-from (DynLib.get lib "inc"))]
(let [lib (Result.unsafe-from-success (DynLib.open "libt.so"))
f (Result.unsafe-from-success (DynLib.get lib "inc"))]
(println* &(Int.str (f 1)))))
```

Expand Down
21 changes: 11 additions & 10 deletions docs/DynLib.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,13 @@ <h1>
<div class="module-description">
<p>DynLib is a module for loading shared libraries at runtime. It
strives to make code loading and calling dynamically easy.</p>
<pre><code>(load &quot;https://github.com/carpentry-org/dynlib@0.0.4&quot;)
<pre><code>(load &quot;https://github.com/carpentry-org/dynlib@0.0.5&quot;)

(defn main []
(println*
&amp;(=&gt; (DynLib.open &quot;libt.so&quot;)
(Maybe.to-result @&quot;Couldn’t open libt.so&quot;)
(Result.and-then
(fn [lib] (Maybe.to-result (DynLib.get lib &quot;inc&quot;)
@&quot;Couldn’t load symbol inc&quot;)))
(fn [lib] (DynLib.get lib &quot;inc&quot;)))
(Result.map (fn [f] (Int.str (f 1)))))))
</code></pre>

Expand Down Expand Up @@ -75,13 +73,14 @@ <h3 id="get">
defn
</div>
<p class="sig">
(Fn [Lib, (Ref String a)] (Maybe b))
(Fn [Lib, (Ref String a)] (Result b String))
</p>
<pre class="args">
(get lib fname)
</pre>
<p class="doc">
<p>gets a function named <code>fname</code> from a shared library <code>lib</code>.</p>
<p>gets a function named <code>fname</code> from a shared library <code>lib</code>. Returns
a <code>Result</code> with the function on success, or the <code>dlerror</code> message on failure.</p>

</p>
</div>
Expand All @@ -95,14 +94,15 @@ <h3 id="get-from-module">
defn
</div>
<p class="sig">
(Fn [Lib, (Ref String a), b] (Maybe c))
(Fn [Lib, (Ref String a), b] (Result c String))
</p>
<pre class="args">
(get-from-module lib md fname)
</pre>
<p class="doc">
<p>gets a function named <code>fname</code> from a Carp module <code>md</code> from inside
a shared library <code>lib</code>.</p>
a shared library <code>lib</code>. Returns a <code>Result</code> with the function on success, or the
<code>dlerror</code> message on failure.</p>

</p>
</div>
Expand All @@ -116,13 +116,14 @@ <h3 id="open">
defn
</div>
<p class="sig">
(Fn [(Ref String a)] (Maybe Lib))
(Fn [(Ref String a)] (Result Lib String))
</p>
<pre class="args">
(open lib)
</pre>
<p class="doc">
<p>opens a shared library <code>lib</code>.</p>
<p>opens a shared library <code>lib</code>. Returns a <code>Result</code> with the library
handle on success, or the <code>dlerror</code> message on failure.</p>

</p>
</div>
Expand Down
37 changes: 22 additions & 15 deletions dynlib.carp
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@
strives to make code loading and calling dynamically easy.

```
(load \"https://github.com/carpentry-org/dynlib@0.0.4\")
(load \"https://github.com/carpentry-org/dynlib@0.0.5\")

(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\")))
(fn [lib] (DynLib.get lib \"inc\")))
(Result.map (fn [f] (Int.str (f 1)))))))
```")
(defmodule DynLib
Expand All @@ -32,28 +30,37 @@ strives to make code loading and calling dynamically easy.
(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")
(private dlerror-)
(hidden dlerror-)
(register dlerror- (Fn [] (Ptr CChar)) "dlerror")
(hidden valid?)
(register valid? (Fn [a] Bool) "DynLib_isvalid")
(private dlerror)
(hidden dlerror)
(defn dlerror []
(let [err (dlerror-)]
(if (valid? err) (String.from-cstr err) @"unknown error")))

(doc open "opens a shared library `lib`.")
(doc open "opens a shared library `lib`. Returns a `Result` with the library
handle on success, or the `dlerror` message on failure.")
(defn open [lib]
(let [l (dlopen (cstr lib) lazy)]
(if (valid? l) (Maybe.Just l) (Maybe.Nothing))))
(if (valid? l) (Result.Success l) (Result.Error (dlerror)))))

(doc get "gets a function named `fname` from a shared library `lib`.")
(doc get "gets a function named `fname` from a shared library `lib`. Returns
a `Result` with the function on success, or the `dlerror` message on failure.")
(defn get [lib fname]
(let [f (dlsym lib (cstr fname))]
(if (valid? f) (Maybe.Just @f) (Maybe.Nothing))))
(if (valid? f) (Result.Success @f) (Result.Error (dlerror)))))

(doc get-from-module
"gets a function named `fname` from a Carp module `md` from inside
a shared library `lib`.")
a shared library `lib`. Returns a `Result` with the function on success, or the
`dlerror` message on failure.")
(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))))
(if (valid? f) (Result.Success @f) (Result.Error (dlerror)))))

(doc close "closes a library `lib`. Either returns nothing or, if an error
occurs, it returns the error message.")
Expand All @@ -63,7 +70,7 @@ occurs, it returns the error message.")
(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)
'(Result.Error e)
(list 'IO.errorln 'e)
'(Result.Success s)
(list set! s 's))))
3 changes: 1 addition & 2 deletions examples/c_and_carp/example.carp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@
(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 "add") @"Couldn’t load symbol")))
(Result.and-then &(fn [lib] (DynLib.get lib "add")))
(Result.map &(fn [f] (Int.str (f 1 2)))))))
4 changes: 1 addition & 3 deletions examples/carp_and_carp/example.carp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
(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-from-module lib "Shared" "add") @"Couldn’t load symbol")))
&(fn [lib] (DynLib.get-from-module lib "Shared" "add")))
(Result.map &(fn [f] (Int.str (f 1 2)))))))
Loading