coffi
Coffi es una biblioteca de interfaz de funciones externas para Clojure, que utiliza la Foreign Function & Memory API en JDK 22 y posteriores. Esto permite llamar código nativo directamente desde Clojure sin la necesidad de Java ni código nativo específico para la biblioteca, como por ejemplo hace JNI. Coffi se enfoca en la facilidad de uso, incluyendo funciones y macros para crear envoltorios que permitan que las funciones nativas resultantes actúen como funciones Clojure, sin embargo, esto no elimina la capacidad de escribir sistemas que minimicen el costo de marshaling de datos y optimicen el rendimiento, para aprovechar el acceso de bajo nivel que nos proporciona la FF&M API.
Instalación
Esta biblioteca está disponible en Clojars, o como dependencia git. Agregue una de las siguientes entradas a la clave:deps de su deps.edn:org.suskalo/coffi {:mvn/version "1.0.615"}
io.github.IGJoshua/coffi {:git/tag "v1.0.615" :git/sha "7401485"}Si utiliza esta biblioteca como una dependencia de git, necesitará preparar la biblioteca.
$ clj -X:deps prepCoffi requiere el uso del paquete java.lang.foreign, y la mayoría de las
operaciones son consideradas inseguras por el JDK, por lo que no están disponibles para
tu código sin pasar algunas opciones en la línea de comandos. Para usar coffi, añade
los siguientes argumentos JVM a tu aplicación.
--enable-native-access=ALL-UNNAMEDPuedes especificar argumentos de JVM en una invocación particular del CLI de Clojure con
la opción -J de la siguiente manera:
`` sh
clj -J--enable-native-access=ALL-UNNAMED
clojure
{:aliases {:dev {:jvm-opts ["--enable-native-access=ALL-UNNAMED"]}}}
También puedes especificarlos en un alias en tu archivo deps.edn bajo la clave
:jvm-opts (ver el siguiente ejemplo) y luego invocar la CLI con ese alias
usando -M, -A o -X.
Otras herramientas de construcción deberían proporcionar una funcionalidad similar si revisas su
documentación.
Al crear un archivo jar ejecutable, puedes evitar la necesidad de pasar este
argumento añadiendo el atributo del manifiesto Enable-Native-Access: ALL-UNNAMED a
tu jar. Consulta la documentación de tu herramienta de construcción para saber cómo agregar esto.
Coffi también incluye soporte para el linter clj-kondo. Si usas clj-kondo y las macros de esta biblioteca no están siendo analizadas correctamente, puede que necesites instalar la configuración incluida con la biblioteca. Puedes hacerlo con el siguiente comando en shell, ejecutado desde el directorio de tu proyecto: sh $ clj-kondo --copy-configs --dependencies --lint "$(clojure -Spath)"
clojure (require '[coffi.mem :as mem]) (require '[coffi.ffi :as ffi :refer [defcfn]])coffi.memUso
Los dos espacios de nombres principales son, que proporciona funciones para asignar y manipular memoria fuera del montón y (de)serializar valores, ycoffi.ffique puede cargar bibliotecas nativas, declarar envoltorios de funciones nativas y (de)serializar funciones como callbacks.
(defcfn strlen "Given a string, measures its length in bytes." strlen [::mem/c-string] ::mem/long)
(strlen "hello") ;; => 5
(ffi/load-system-library "z")
`
En el espacio de nombres coffi.mem hay tipos para todos los tipos numéricos primitivos con signo en C, además de ::mem/pointer y ::mem/c-string, y formas de usar declaraciones de tipo al estilo malli para definir structs, unions, arrays, enums y flagsets.
Alternativas
Esta biblioteca no es la única biblioteca de Clojure que proporciona acceso a código nativo. Además, existen las siguientes bibliotecas (entre otras):Dtype-next tiene soporte para versiones de Java 8-15, 17+ y GraalVM, pero está fuertemente enfocado en la programación basada en arrays, así como en mantener la memoria en el lado nativo en lugar de transformar datos hacia y desde estructuras nativas de Clojure. En Java 17+, usa la API de Funciones y Memoria Externas (una parte de Project Panama hasta su estabilización en JDK 22), mientras que en otras versiones de Java usa JNA.Tech.jna y clojure-jna usan ambas la biblioteca JNA en todos los casos, y ninguna proporciona soporte explícito para callbacks. JNA permite el uso de java.nio.ByteBuffers para pasar structs por valor, y ambas bibliotecas ofrecen formas de usar esta construcción por valor para llamar a APIs por referencia.
Una alternativa adicional a coffi es usar directamente JNI, que es el método más antiguo para envolver código nativo en la JVM, pero tiene la desventaja de que requiere escribir código nativo y Java para usarlo, incluso si solo se pretende usar desde Clojure.
Si tu aplicación necesita poder ejecutarse en versiones anteriores a la 22 de la JVM, deberías considerar estas otras opciones. Dtype-next ofrece el soporte más robusto para código nativo, pero si estás envolviendo una biblioteca simple, las otras bibliotecas pueden ser más atractivas, ya que tienen una superficie de API más pequeña y es más fácil envolver funciones.
También existe un resumen de terceros de opciones FFI para Clojure.
Problemas Conocidos
El autor del proyecto está al tanto de estos problemas y planea solucionarlos en una futura versión:- Al generar documentación con codox en una biblioteca que depende de coffi, se producirá el siguiente error. Una solución temporal es agregar una dependencia explícita en su compilación de codox sobre insn en la versión 0.2.1
Unable to find static field: ACC_OPEN in interface org.objectweb.asm.Opcodes
``
Planes Futuros
Estas características están planificadas para futuras versiones.- Soporte para tipo va_args
- Herramienta de análisis de encabezados para generar un modelo de datos? (¿quizás solo trabajar con clong?)
- Alias de tipos genéricos
- Tipos de enteros sin signo
- Macro auxiliar para argumentos de salida
- Mejorar mensajes de error del macro defcfn
- Memoria mapeada
- Macros auxiliares para implementaciones personalizadas de serde para tipos de datos más compuestos
- Soporte para GraalVM Native Image (una vez que su soporte para FFM sea maduro)
Licencia
Copyright © 2023 Joshua Suskalo
Distribuido bajo la Licencia Pública de Eclipse versión 1.0.
--- Tranlated By Open Ai Tx | Last indexed: 2025-11-30 ---