Разберем использование Java Native Access на простом примере в Clojure.
Для начала необходимо скачать jna.jar с github.com
и добавить в новый проект clojure, созданный через утилиту lein:
(defproject jna "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.4.0"]]
:plugins [[lein-swank "1.4.5"]]
:resource-paths ["resources/jna-4.0.0.jar"])
После чего необходимо добавить импорт в ns:
(ns jna.core
(:import (com.sun.jna Library Function)))
Следующий шаг это создание нативной библиотеки:
#ifndef FOO_H
#define FOO_H
extern int foo(int a, int b);
#endif
#include "foo.h"
int foo(int a, int b)
{
return a + b;
}
gcc -c -Wall -Werror -fpic foo.c
gcc -shared -o libfoo.so foo.o
Один из вариантов вызова нативных функций это использование интерфейса:
(def foo-interface (gen-interface
:name foo-test
:extends [com.sun.jna.Library]
:methods [[foo [Integer Integer] Integer]]))
Второй этап этой процедуры это загрузка самой библиотеки:
(def native-lib (Native/loadLibrary "clib/libfoo.so" foo-interface))
И последний этап это определение самой функции:
(defn native-foo [a b]
(.foo native-lib (Integer. a) (Integer. b)))
Преобразование входных переменных к типу Integer необходимо из-за того, что при вызове функции с целыми числами они являются типом Long.
Еще одним вариантом вызова нативных функций - это использование класса Function. На просторах интернета я нашел достаточно интересный макрос:
(defmacro jna-call [lib func ret & args]
`(let [library# (name ~lib)
function# (Function/getFunction library# ~func)]
(.invoke function# ~ret (to-array [~@args]))))
Но опять же необходимо не забывать, что при передаче простых чисел они имеют тип Long.