Interfaz para llamar funciones desde otros lenguajes de programación.
Una interfaz de función externa ( FFI ) es un mecanismo mediante el cual un programa escrito en un lenguaje de programación puede llamar a rutinas o hacer uso de servicios escritos o compilados en otro. Una FFI se utiliza a menudo en contextos donde se realizan llamadas a una biblioteca binaria de vínculos dinámicos .
Nombrar
El término proviene de la especificación de Common Lisp , que se refiere explícitamente a la característica del lenguaje de programación que permite llamadas entre idiomas como tal; [ cita necesaria ] el término también se utiliza a menudo oficialmente en la documentación del intérprete y compilador de Haskell , [1] Rust , [2] PHP , [3] Python y LuaJIT ( Lua ) [4] [5] : 35 . [6] Otros lenguajes usan otra terminología: Ada tiene enlaces de lenguaje , mientras que Java tiene Java Native Interface (JNI) o Java Native Access (JNA). La interfaz de función externa se ha convertido en una terminología genérica para los mecanismos que brindan dichos servicios.
Operación
La función principal de una interfaz de función externa es combinar la semántica y las convenciones de llamada de un lenguaje de programación (el lenguaje anfitrión o el lenguaje que define el FFI), con la semántica y las convenciones de otro (el lenguaje invitado ). Este proceso también debe tener en cuenta los entornos de ejecución y las interfaces binarias de aplicaciones de ambos. Esto se puede hacer de varias maneras:
- Requerir que las funciones del idioma invitado que serán invocables en el idioma anfitrión se especifiquen o implementen de una manera particular, a menudo utilizando una biblioteca de compatibilidad de algún tipo.
- Uso de una herramienta para envolver automáticamente funciones del idioma invitado con el código adhesivo apropiado , que realiza cualquier traducción necesaria.
- Uso de una biblioteca contenedora
- Restringir el conjunto de capacidades del idioma anfitrión que se pueden utilizar en varios idiomas. Por ejemplo, las funciones de C++ llamadas desde C no pueden (en general) incluir parámetros de referencia ni generar excepciones.
Las FFI pueden verse complicadas por las siguientes consideraciones:
- Si un idioma admite la recolección de basura (GC) y el otro no; Se debe tener cuidado de que el código de lenguaje que no es GC no haga nada que provoque que falle el GC en el otro. En JNI, por ejemplo, el código C que "conserva" las referencias de objetos que recibe de Java debe comunicar esta información con éxito a la máquina virtual Java o al Java Runtime Environment (JRE); de lo contrario, Java puede eliminar objetos antes de que C termine con ellos. . (El código C también debe liberar explícitamente su vínculo con dicho objeto una vez que C ya no necesite ese objeto).
- Los objetos o tipos de datos complicados o no triviales pueden resultar difíciles de asignar de un entorno a otro.
- Es posible que ambos idiomas no puedan mantener referencias a la misma instancia de un objeto mutable debido al problema de mapeo mencionado anteriormente.
- Es posible que uno o ambos idiomas se estén ejecutando en una máquina virtual (VM); además, si ambos lo son, a menudo se trata de máquinas virtuales diferentes.
- La herencia entre idiomas y otras diferencias, como entre sistemas de tipos o entre modelos de composición de objetos , pueden resultar especialmente difíciles.
![UML ffi.svg](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
Ejemplos de FFI incluyen:
- Enlaces de lenguaje Ada , que permiten no solo llamar a funciones externas sino también exportar sus funciones y métodos para ser llamados desde código que no sea Ada. [7]
- C++ tiene un FFI trivial con C , ya que los lenguajes comparten un subconjunto común significativo. El efecto principal de la declaración "C" externa en C++ es deshabilitar la alteración de nombres de C++ . Con otros lenguajes, se utilizan utilidades o middleware separados, los ejemplos incluyen:
- Clean proporciona un FFI bidireccional con todos los idiomas siguiendo C o la convención de llamada stdcall . [8] [9]
- ceceo común
- Interfaz nativa compilada (CNI), alternativa a JNI utilizada en el entorno del compilador GNU.
- Una de las bases del Modelo de objetos componentes es un formato de interfaz común, que utiliza de forma nativa los mismos tipos que Visual Basic para cadenas y matrices.
- D lo hace de la misma manera que C++ , desde "C" externo hasta externo (C++)
- Dart incluye la biblioteca dart:ffi [10] para llamar código C nativo para aplicaciones móviles, de línea de comandos y de servidor.
- Los lenguajes de programación dinámicos , como Python , Perl , Tcl y Ruby , brindan fácil acceso al código nativo escrito en C, C++ o cualquier otro lenguaje que obedezca las convenciones de llamadas de C/C++.
- Factor tiene FFI para C, Fortran, Objective-C y Windows COM; todos estos permiten importar y llamar dinámicamente bibliotecas compartidas arbitrarias.
- Fortran 2003 tiene un módulo ISO_C_BINDING que proporciona tipos de datos interoperables (tanto tipos intrínsecos como estructuras POD), punteros interoperables, almacenes de datos globales interoperables y mecanismos para llamar a C desde Fortran y para llamar a Fortran desde C. [11] Se ha mejorado en el estándar Fortran 2018.
- Go puede llamar al código C directamente a través del
"C"
pseudopaquete. [12] - Google Web Toolkit (GWT), en el que Java se compila en JavaScript, tiene un FFI llamado JSNI que permite que el código fuente de Java llame a funciones JavaScript arbitrarias y que JavaScript vuelva a llamar a Java.
- Haskell
- Interfaz nativa de Java (JNI), que proporciona una interfaz entre Java y C/C++, los lenguajes de sistema preferidos en la mayoría de los sistemas donde se implementa Java. Java Native Access (JNA) proporciona una interfaz con bibliotecas nativas sin tener que escribir código adhesivo . Otro ejemplo es JNR.
- LuaJIT, una implementación justo a tiempo de Lua , tiene un FFI que permite "llamar a funciones C externas y usar estructuras de datos C a partir de código Lua puro". [4] [5] : 35
- Nim tiene un FFI que le permite utilizar código fuente de C , C++ y Objective-C . También puede interactuar con JavaScript.
- JavaScript generalmente se ejecuta dentro de los tiempos de ejecución del navegador web que no brindan acceso directo a las bibliotecas del sistema ni a los comandos para ejecutar, pero hay algunas excepciones:
- Node.js proporciona funciones para abrir
.node
módulos precompilados que a su vez pueden proporcionar acceso a recursos no integrados. - Deno , proporciona un tipo de interfaz FFI a través de
dlopen(...)
funciones. [13] - Bun proporciona un módulo integrado,
bun:ffi
para llamar de manera eficiente a bibliotecas nativas directamente desde JavaScript. [14]
- Julia tiene
ccall
una palabra clave para llamar a C (y otros lenguajes, por ejemplo, Fortran); [15] mientras que los paquetes, que brindan soporte similar sin repeticiones, están disponibles para algunos lenguajes, por ejemplo, para Python [16] (para, por ejemplo, proporcionar soporte OO y soporte GC), Java (y admite otros lenguajes JDK, como Scala) y R. El uso interactivo con C++ también es posible con el paquete Cxx.jl. - PhoneGap (antes se llamaba Apache Callback, pero ahora es Apache Cordova ) es una plataforma para crear aplicaciones móviles nativas utilizando HTML, CSS y JavaScript. Además, tiene FFI a través de funciones de devolución de llamada de JavaScript para acceder a métodos y propiedades de las funciones nativas del teléfono móvil, incluidos acelerómetro, cámara (también PhotoLibrary y SavedPhotoAlbum), brújula, almacenamiento (base de datos SQL y localStorage), notificación, medios y captura (reproducción y grabación). o audio y video), archivo, contactos (libreta de direcciones), eventos, dispositivo e información de conexión.[1],[2].
- PHP proporciona FFI a C. [17]
- Python proporciona los módulos ctypes y cffi. Por ejemplo, el módulo ctypes puede cargar funciones C desde una biblioteca compartida o una biblioteca de vínculos dinámicos (DLL) sobre la marcha y traducir tipos de datos simples automáticamente entre la semántica de Python y C de la siguiente manera:
importar ctypes libc = ctypes . CDLL ( '/lib/libc.so.6' ) # En Linux/Unix t = libc . time ( Ninguno ) # Código C equivalente: t = time(NULL) print ( t )
- P/Invoke , que proporciona una interfaz entre Microsoft Common Language Runtime y el código nativo.
- Racket tiene un FFI nativo basado en gran medida en macros que permite importar bibliotecas compartidas arbitrarias de forma dinámica. [18] [19]
- Raku puede llamar a Ruby , Python , Perl , Brainfuck , Lua , C , C++ , Go , Scheme ( Guile , Gambit ) y Rust [20] [21]
- Ruby proporciona FFI a través de la gema ffi o mediante el violín de la biblioteca estándar.
Requiere 'violín' libm = Violín . dlopen ( '/lib/libm.so.6' ) # Equivalente a: doble piso(doble x); piso = Violín :: Función . new ( libm . sym ( 'floor' ), # ptr es una función (o símbolo) referenciada de un Fiddle::Handle. [ Fiddle :: TYPE_DOUBLE ] , # args es una matriz de argumentos, pasada a la función ptr Fiddle :: TYPE_DOUBLE # ret_type es el tipo de retorno de la función ) # Equivalente a: piso(3.14159); piso . llamar ( 3. 14159 ) #=> 3.0
- Rust define una interfaz de función externa para funciones con varias interfaces binarias de aplicaciones (ABI) estándar. [22] También hay una biblioteca para interactuar con Elixir , Rustler.
- Visual Basic tiene una sintaxis declarativa que le permite llamar a funciones C que no son Unicode.
- Wolfram Language proporciona una tecnología llamada Wolfram Symbolic Transfer Protocol (WSTP) que permite llamadas bidireccionales de código entre otros lenguajes con enlaces para C++, Java, .NET . y otros idiomas.
- Zig proporciona FFI a C utilizando la
cImport
función incorporada. [23]
Además, muchas FFI se pueden generar automáticamente: por ejemplo, SWIG . Sin embargo, en el caso de un lenguaje de extensión, puede ocurrir una inversión semántica de la relación entre el huésped y el anfitrión, cuando un cuerpo más pequeño de lenguaje de extensión es el invitado que invoca servicios en el cuerpo más grande del lenguaje anfitrión, como escribir un pequeño complemento [24 ] para GIMP. [25]
Algunas FFI están restringidas a funciones independientes , mientras que otras también permiten llamadas a funciones integradas en un objeto o clase (a menudo llamadas llamadas a métodos ); algunos incluso permiten la migración de tipos de datos u objetos complejos a través de la frontera del idioma.
En la mayoría de los casos, una FFI se define mediante un lenguaje de nivel superior , de modo que puede emplear servicios definidos e implementados en un lenguaje de nivel inferior , normalmente un lenguaje de programación de sistemas como C o C++ . Por lo general, esto se hace para acceder a los servicios del sistema operativo (SO) en el idioma en el que está definida la API del sistema operativo o para objetivos de rendimiento.
Muchas FFI también proporcionan los medios para que el idioma llamado invoque servicios también en el idioma anfitrión.
El término interfaz de función externa generalmente no se utiliza para describir tiempos de ejecución multilingües como Microsoft Common Language Runtime , donde se proporciona un sustrato común que permite que cualquier lenguaje compatible con CLR utilice servicios definidos en cualquier otro. (Sin embargo, en este caso, CLR incluye un FFI, P/Invoke , para llamar fuera del tiempo de ejecución). Además, muchas arquitecturas informáticas distribuidas, como la invocación de método remoto Java (RMI), RPC, CORBA , SOAP y D- Los autobuses permiten que diferentes servicios se escriban en diferentes idiomas; Estas arquitecturas generalmente no se consideran FFI.
Casos especiales
Hay algunos casos especiales, en los que los lenguajes se compilan en la misma máquina virtual de código de bytes, como Clojure y Java , así como Elixir y Erlang . Al no tener interfaz, no es un FFI estrictamente hablando, aunque ofrece las mismas funciones al usuario.
Ver también
Referencias
- ^ "Introducción a FFI". HaskellWiki . Consultado el 19 de junio de 2015 .
El FFI de Haskell se utiliza para llamar funciones de otros lenguajes (básicamente C en este punto), y para que C llame a funciones de Haskell.
- ^ "estándar::ffi". Rust-lang.org . Consultado el 1 de abril de 2021 .
Este módulo proporciona utilidades para manejar datos a través de interfaces que no son Rust, como otros lenguajes de programación y el sistema operativo subyacente. Se utiliza principalmente para enlaces y códigos FFI (Foreign Function Interface) que necesitan intercambiar cadenas tipo C con otros lenguajes.
- ^ "Manual PHP FFI". Manual PHP . Consultado el 31 de agosto de 2023 .
Las variables C definidas están disponibles como propiedades de la instancia de FFI.
- ^ ab Mike Pall. "Biblioteca FFI". Luajit.org . Consultado el 29 de septiembre de 2013 .
- ^ ab Heintz, Joaquín; Hofmann, Alex; McCurdy, Iain (2013). Caminos a seguir: Actas de la Primera Conferencia Internacional Csound. Newcastle upon Tyne: Cambridge Scholars Publishing. ISBN 978-1-4438-5122-0. OCLC 855505215.
- ^ "Documentación CFFI" . Consultado el 19 de junio de 2015 .
Interfaz de función externa C para Python. El objetivo es proporcionar una manera conveniente y confiable de llamar código C compilado desde Python usando declaraciones de interfaz escritas en C.
- ^ "Interfaz con otros idiomas". Adaic.org . Consultado el 29 de septiembre de 2013 .
- ^ "Exportación exterior" . Consultado el 25 de mayo de 2020 .
- ^ "Llamar a C desde limpio" . Consultado el 25 de abril de 2018 .
- ^ "biblioteca dart:ffi" . Consultado el 1 de enero de 2020 .
- ^ "'wiki de etiquetas 'fortran-iso-c-binding'". Desbordamiento de pila .
- ^ "go". Ir a lenguaje de programación . Consultado el 23 de agosto de 2015 .
- ^ "Interfaz de funciones externas | Manual". Deno . Consultado el 8 de febrero de 2023 .
- ^ "API de FFI". Documentos de pan .
- ^ "Llamar a C y código Fortran". JuliaLang.org . Consultado el 11 de febrero de 2018 .
- ^ PyCall.jl: Paquete para llamar a funciones de Python desde el lenguaje Julia, JuliaPy, 2018-02-08 , consultado el 11 de febrero de 2018
- ^ "PHP: FFI - Manual". El grupo PHP . Consultado el 13 de junio de 2019 .
- ^ Eli Barzilay. "La interfaz exterior de la raqueta". Docs.racket-lang.org . Consultado el 29 de septiembre de 2013 .
- ^ "TR600.pdf" (PDF) . Archivado desde el original (PDF) el 2 de septiembre de 2009 . Consultado el 29 de septiembre de 2013 .
- ^ "Implementaciones en línea" . Consultado el 15 de agosto de 2017 .
- ^ "Llamada nativa" . Consultado el 15 de agosto de 2017 .
- ^ "Uso de funciones externas para llamar a un código externo" . Consultado el 1 de junio de 2019 .
- ^ "Importar desde archivo de encabezado C". Fundación de software Zig . Consultado el 11 de marzo de 2021 .
- ^ "4. Un guión de muestra". Gimp.org. 2001-02-04 . Consultado el 29 de septiembre de 2013 .
- ^ "Script-Fu y complementos para The GIMP". Gimp.org . Consultado el 29 de septiembre de 2013 .
enlaces externos
- c2.com: interfaz de función externa
- Interfaz de función externa Haskell 98
- Allegro Common Lisp FFI
- Un generador de interfaz de función externa para occam-pi
- UFFI: Interfaz de función externa universal Lisp
- CFFI: Interfaz de función externa común, para Common Lisp
- Interfaz nativa de Java: guía y especificaciones del programador
- La especificación JNI
- JSNI (interfaz nativa de JavaScript)
- Biblioteca dyncall que utiliza núcleos de llamadas ensambladas para una variedad de procesadores, sistemas operativos y convenciones de llamadas.
- FFCLLAMADA
- C/Invocar
- libfi