Move library loading interop to a java class

This commit is contained in:
Joshua Suskalo 2021-09-23 08:15:16 -05:00
parent ad2c3d3606
commit 1fe9d2cb02
4 changed files with 59 additions and 6 deletions

View file

@ -19,7 +19,8 @@
(def lib-coord 'org.suskalo/coffi) (def lib-coord 'org.suskalo/coffi)
(def version (format "0.1.%s-SNAPSHOT" (b/git-count-revs nil))) (def version (format "0.1.%s-SNAPSHOT" (b/git-count-revs nil)))
(def source-dirs ["src/"]) (def source-dirs ["src/clj/"])
(def java-source-dirs ["src/java/"])
(def c-test-dirs ["test/c/"]) (def c-test-dirs ["test/c/"])
@ -42,6 +43,15 @@
[& path-components] [& path-components]
(.exists ^java.io.File (apply io/file path-components))) (.exists ^java.io.File (apply io/file path-components)))
(defn compile-java
"Compiles java classes required for interop."
[opts]
(.mkdirs (io/file class-dir))
(b/process {:command-args ["javac" "--add-modules=jdk.incubator.foreign"
"src/java/coffi/ffi/Loader.java"
"-d" class-dir]})
opts)
(defn- write-pom (defn- write-pom
"Writes a pom file if one does not already exist." "Writes a pom file if one does not already exist."
[opts] [opts]

View file

@ -1,4 +1,4 @@
{:paths ["src"] {:paths ["src" "target/classes"]
:deps {org.clojure/clojure {:mvn/version "1.10.3"} :deps {org.clojure/clojure {:mvn/version "1.10.3"}
insn/insn {:mvn/version "0.2.1"}} insn/insn {:mvn/version "0.2.1"}}
:aliases :aliases

View file

@ -7,6 +7,7 @@
(:import (:import
(clojure.lang (clojure.lang
IDeref IFn IMeta IObj IReference) IDeref IFn IMeta IObj IReference)
(coffi.ffi Loader)
(java.lang.invoke (java.lang.invoke
MethodHandle MethodHandle
MethodHandles MethodHandles
@ -567,19 +568,18 @@
(defn load-system-library (defn load-system-library
"Loads the library named `libname` from the system's load path." "Loads the library named `libname` from the system's load path."
[libname] [libname]
(System/loadLibrary (name libname))) (Loader/loadSystemLibrary (name libname)))
(defn load-library (defn load-library
"Loads the library at `path`." "Loads the library at `path`."
[path] [path]
(System/load (.getAbsolutePath (io/file path)))) (Loader/loadLibrary (.getAbsolutePath (io/file path))))
(defn find-symbol (defn find-symbol
"Gets the [[MemoryAddress]] of a symbol from the loaded libraries." "Gets the [[MemoryAddress]] of a symbol from the loaded libraries."
[sym] [sym]
(let [sym (name sym)] (let [sym (name sym)]
(or (.. (CLinker/systemLookup) (lookup sym) (orElse nil)) (Loader/findSymbol sym)))
(.. (SymbolLookup/loaderLookup) (lookup sym) (orElse nil)))))
(defn- method-type (defn- method-type
"Gets the [[MethodType]] for a set of `args` and `ret` types." "Gets the [[MethodType]] for a set of `args` and `ret` types."

View file

@ -0,0 +1,43 @@
package coffi.ffi;
import jdk.incubator.foreign.*;
/**
* Loading libraries with the {@link System#load} and {@link System#loadLibrary}
* relies on the classloader, which Clojure messes with. This class exists to
* have a consistent classloader, providing a consistent way to load libraries
* and symbols from them.
*/
public class Loader {
/**
* Loads a library from a given absolute file path.
*
* @param filepath The absolute file path of the library to load
*/
public static void loadLibrary(String filepath) {
System.load(filepath);
}
/**
* Loads a library on the system loadpath with the given name.
*
* @param libname The library name, stripped of platform-specific prefixes and suffixes.
*/
public static void loadSystemLibrary(String libname) {
System.loadLibrary(libname);
}
/**
* Load the memory address of a symbol.
*
* First attempts to load the symbol from system libraries, like libc, and
* afterwards attempts to load the symbol from other libraries.
*
* @param symbol The name of the symbol to load from a library.
*/
public static MemoryAddress findSymbol(String symbol) {
return CLinker.systemLookup().lookup(symbol)
.orElseGet(() -> SymbolLookup.loaderLookup().lookup(symbol).orElse(null));
}
}