Add :lazy option for ffi/context for jpm quickbin usage.

This commit is contained in:
Calvin Rose 2022-06-13 21:26:03 -05:00
parent 105ba5e124
commit 80729353c8
2 changed files with 55 additions and 16 deletions

View File

@ -1,4 +1,8 @@
(ffi/context "/usr/lib/libgtk-3.so")
# :lazy true needed for jpm quickbin
# lazily loads library on first function use
# so the `main` function
# can be marshalled.
(ffi/context "/usr/lib/libgtk-3.so" :lazy true)
(ffi/defbind
gtk-application-new :ptr
@ -33,13 +37,13 @@
gtk-button-set-label :void
[a :ptr b :ptr])
(def cb (ffi/trampoline :default))
(def cb (delay (ffi/trampoline :default)))
(defn on-active
[app]
(def window (gtk-application-window-new app))
(def btn (gtk-button-new-with-label "Click Me!"))
(g-signal-connect-data btn "clicked" cb
(g-signal-connect-data btn "clicked" (cb)
(fn [btn] (gtk-button-set-label btn "Hello World"))
nil 1)
(gtk-container-add window btn)
@ -48,5 +52,5 @@
(defn main
[&]
(def app (gtk-application-new "org.janet-lang.example.HelloApp" 0))
(g-signal-connect-data app "activate" cb on-active nil 1)
(g-signal-connect-data app "activate" (cb) on-active nil 1)
(g-application-run app 0 nil))

View File

@ -3614,9 +3614,26 @@
###
###
(defmacro delay
"Lazily evaluate a series of expressions. Returns a function that
returns the result of the last expression. Will only evaluate the
body once, and then memoizes the result."
[& forms]
(def state (gensym))
(def loaded (gensym))
~((fn []
(var ,state nil)
(var ,loaded nil)
(fn []
(if ,loaded
,state
(do
(set ,loaded true)
(set ,state (do ,;forms))))))))
(compwhen (dyn 'ffi/native)
(defdyn *ffi-context*" Current native library for ffi/bind and other settings")
(defdyn *ffi-context* " Current native library for ffi/bind and other settings")
(defn- default-mangle
[name &]
@ -3625,12 +3642,16 @@
(defn ffi/context
"Set the path of the dynamic library to implictly bind, as well
as other global state for ease of creating native bindings."
[native-path &named map-symbols]
(def lib (ffi/native native-path))
[native-path &named map-symbols lazy]
(default map-symbols default-mangle)
(def lib (if lazy nil (ffi/native native-path)))
(def lazy-lib (if lazy (delay (ffi/native native-path))))
(setdyn *ffi-context*
{:native lib
:map-symbols map-symbols}))
@{:native-path native-path
:native lib
:native-lazy lazy-lib
:lazy lazy
:map-symbols map-symbols}))
(defmacro ffi/defbind
"Generate bindings for native functions in a convenient manner."
@ -3639,14 +3660,28 @@
(def arg-pairs (partition 2 (last body)))
(def formal-args (map 0 arg-pairs))
(def type-args (map 1 arg-pairs))
(def ctx (dyn *ffi-context*))
(def raw-symbol ((get ctx :map-symbols default-mangle) name))
(def ffi-mod (get ctx :native))
(def ptr (assert (ffi/lookup ffi-mod raw-symbol) "failed to find symbol"))
(def computed-type-args (eval ~[,;type-args]))
(def sig (ffi/signature :default ret-type ;computed-type-args))
~(defn ,name ,;meta [,;formal-args]
(,ffi/call ,ptr ,sig ,;formal-args))))
(def {:native lib
:native-path np
:lazy lazy
:native-lazy llib
:map-symbols ms} (assert (dyn *ffi-context*) "no ffi context found"))
(def raw-symbol (ms name))
(if lazy
(let [ptr
(delay
(assert (ffi/lookup (llib) raw-symbol) "failed to find symbol"))
sig
(delay
(ffi/signature :default ret-type ;computed-type-args))]
~(defn ,name ,;meta [,;formal-args]
(,ffi/call (,ptr) (,sig) ,;formal-args)))
(let [ptr
(assert (ffi/lookup lib raw-symbol) "failed to find symbol")
sig
(ffi/signature :default ret-type ;computed-type-args)]
~(defn ,name ,;meta [,;formal-args]
(,ffi/call ,ptr ,sig ,;formal-args))))))
###
###