Interfață funcție străină - Foreign function interface
O interfață cu funcții străine ( FFI ) este un mecanism prin care un program scris într-un limbaj de programare poate apela rutine sau poate utiliza servicii scrise în altul.
Denumire
Termenul provine din specificația pentru Common Lisp , care se referă în mod explicit la caracteristicile de limbă pentru apelurile inter-limbă ca atare; termenul este folosit și oficial de limbajele de programare Haskell , Rust și Python . Alte limbi folosesc alte terminologii: limbajul de programare Ada vorbește despre „ legături de limbaj ”, în timp ce Java se referă la FFI-ul său ca JNI ( Java Native Interface ) sau JNA ( Java Native Access ). Interfața funcției străine a devenit o terminologie generică pentru mecanismele care furnizează astfel de servicii.
Operațiune
Funcția principală a unei interfețe de funcții străine este de a asocia semantica și convențiile de apelare ale unui limbaj de programare (limbajul gazdă sau limbajul care definește FFI), cu semantica și convențiile altui ( limbajul invitat ). Acest proces trebuie să ia în considerare și mediile de execuție și / sau interfețele binare ale aplicației ambelor. Acest lucru se poate face în mai multe moduri:
- Solicitarea ca funcțiile de limbă de oaspeți care pot fi apelate în limbajul gazdă să fie specificate sau implementate într-un mod particular, folosind adesea o bibliotecă de compatibilitate de un fel.
- Utilizarea unui instrument pentru a „înfășura” automat funcțiile de limbă de oaspeți cu un cod de lipire adecvat , care efectuează orice traducere necesară.
- Utilizarea bibliotecilor de împachetare
- Restricționarea setului de capabilități de limbă gazdă care pot fi utilizate în mai multe limbi. De exemplu, funcțiile C ++ apelate de la C nu pot (în general) să includă parametri de referință sau să arunce excepții.
FFI-urile pot fi complicate de următoarele considerații:
- Dacă o limbă acceptă colectarea gunoiului (GC) și cealaltă nu; trebuie avut grijă ca codul de limbă non-GC să nu facă nimic pentru ca GC în celălalt să eșueze. În JNI, de exemplu, codul C care „ține” referințele la obiect pe care le primește de la Java trebuie să „înregistreze” acest fapt în mediul de execuție Java (JRE); în caz contrar, Java poate șterge obiecte înainte ca C să fi terminat cu ele. (Codul C trebuie, de asemenea, să-și elibereze în mod explicit linkul către un astfel de obiect, odată ce C nu mai are nevoie de acel obiect.)
- Obiectele sau tipurile de date complicate sau non-banale pot fi dificil de cartografiat de la un mediu la altul.
- Este posibil ca ambele limbi să nu poată menține referințe la aceeași instanță a unui obiect modificabil, din cauza problemei de mapare de mai sus.
- Una sau ambele limbi pot rula pe o mașină virtuală (VM); în plus, dacă ambele sunt, acestea vor fi probabil VM-uri diferite.
- Moștenirea între limbi și alte diferențe, cum ar fi între sistemele de tip sau între modelele de compoziție a obiectelor , pot fi deosebit de dificile.
După limbă
Exemple de FFI-uri includ:
- Legături de limbă Ada , permițând nu numai să apelați funcții străine, ci și să exportați funcțiile și metodele sale pentru a fi apelate din cod non-Ada.
- C ++ are un FFI trivial cu C , deoarece limbile au un subset comun semnificativ. Efectul principal al declarației externe „C” în C ++ este de a dezactiva modificarea numelui C ++ .
- Clean oferă un FFI bidirecțional cu toate limbile după C sau convenția de apelare stdcall .
- CNI , alternativă la JNI utilizată în mediul de compilare GNU.
- D o face la fel ca C ++ , cu extern "C" prin extern (C ++)
- Dart include biblioteca dart: ffi pentru a apela codul nativ C pentru aplicații mobile, de linie de comandă și de server
- Limbile dinamice , cum ar fi Python , Perl , Tcl și Ruby , oferă acces ușor la codul nativ scris în C / C ++ (sau în orice alt limbaj care respectă convențiile de apelare C / C ++).
- Factor are FFI-uri pentru C, Fortran , Objective-C și Windows COM ; toate acestea permit importarea și apelarea dinamică a bibliotecilor partajate arbitrare.
- FFI-urile din Common Lisp și Haskell
- Fortran 2003 are un modul ISO_C_BINDING care oferă tipuri de date interoperabile (atât tipuri intrinseci, cât și structuri POD), indicatori interoperabili, depozite de date globale interoperabile și mecanisme pentru apelarea C de la Fortran și pentru apelarea Fortran de la C. A fost îmbunătățit în Fortran 2018 standard.
-
Go poate apela codul C direct prin
"C"pseudo-pachet. - GWT , în care Java este compilat în JavaScript, are un FFI numit JSNI care permite sursei Java să apeleze funcții JavaScript arbitrare, iar JavaScript să revină în Java.
- JNI , care oferă o interfață între Java și C / C ++, limbile de sistem preferate pe majoritatea sistemelor în care este implementat Java. JNA oferă o interfață cu biblioteci native fără a fi nevoie să scrieți cod de lipici . Un alt exemplu este JNR
- Nim are un FFI care îi permite să utilizeze sursa din C , C ++ și Objective-C . De asemenea, poate interfața cu Javascript.
-
Julia are un
ccallcuvânt cheie pentru a apela C (și alte limbi, de exemplu, Fortran); în timp ce pachetele, care oferă suport similar fără boilerplate, sunt disponibile pentru unele limbi, de exemplu pentru Python (de exemplu, pentru a oferi suport OO și suport GC), Java (și acceptă alte limbi JDK, cum ar fi Scala) și R. Utilizarea interactivă cu C ++ este posibil și cu pachetul Cxx.jl. - PHP furnizează FFI către C.
- Ruby oferă FFI , fie prin FFI bijuterie, sau prin biblioteca standard cetera .
require 'fiddle'
libm = Fiddle.dlopen('/lib/libm.so.6')
# Equivalent to: double floor(double x);
floor = Fiddle::Function.new(
libm.sym('floor'), # ptr is a referenced function(, or symbol), of a Fiddle::Handle.
[Fiddle::TYPE_DOUBLE], # args is an Array of arguments, passed to the ptr function.
Fiddle::TYPE_DOUBLE # ret_type is the return type of the function
)
# Equivalent to: floor(3.14159);
floor.call(3.14159) #=> 3.0
-
Python oferă ctypes și module cffi . De exemplu, modulul ctypes poate încărca funcții C din biblioteci partajate / DLL - uri din mers și poate traduce automat tipuri de date simple între Python și C semantică după cum urmează:
import ctypes libc = ctypes.CDLL('/lib/libc.so.6') # Under Linux/Unix t = libc.time(None) # Equivalent C code: t = time(NULL) print(t)
- P / Invoke , care oferă o interfață între Microsoft Common Language Runtime și codul nativ.
- Racket are un FFI nativ bazat puternic pe macrocomenzi care permite importul dinamic al bibliotecilor partajate arbitrare.
- Raku poate apela Ruby , Python , Perl , Brainfuck , Lua , C , C ++ , Go și Scheme Guile / Gambit
- Rust definește, de asemenea, o interfață de funcție străină.
- Visual Basic are o sintaxă declarativă care îi permite să apeleze funcții non-Unicode C.
- Una dintre bazele Modelului de obiecte componente este un format comun de interfață, care folosește nativ aceleași tipuri ca Visual Basic pentru șiruri și matrice.
- LuaJIT, o implementare just-in-time a Lua , are un FFI care permite „apelarea funcțiilor C externe și utilizarea structurilor de date C din cod Lua pur”.
- PhoneGap (a fost denumit Apache Callback, dar acum Apache Cordova) este o platformă pentru construirea de aplicații mobile native folosind HTML, CSS și JavaScript. În plus, are FFI-uri prin funcții de apel invers JavaScript pentru acces la metodele și proprietățile caracteristicilor native ale telefonului mobil, inclusiv Accelerometru, Cameră foto (de asemenea PhotoLibrary și SavedPhotoAlbum), Busolă, Stocare (bază de date SQL și localStorage), Notificare, Media și Captură (redare și înregistrare sau audio) și video), Fișier, Contacte (agendă), Evenimente, informații despre dispozitiv și conexiune. [1] , [2] .
- Wolfram Language oferă o tehnologie numită WSTP (Wolfram Symbolic Transfer Protocol) care permite apelarea bidirecțională a codului între alte limbi cu legături pentru C ++, Java, .NET și alte limbi.
-
Zig oferă FFI la c folosind
cImportfuncția încorporată .
În plus, multe FFI-uri pot fi generate automat: de exemplu, SWIG . Cu toate acestea, în cazul unui limbaj de extensie , se poate produce o inversare semantică a relației dintre oaspeți și gazde, atunci când un corp mai mic de limbaj de extensie este invitatul care invocă servicii în corpul mai mare de limbă gazdă, cum ar fi scrierea unui mic plugin pentru GIMP .
Unele FFI-uri sunt limitate la funcții independente , în timp ce altele permit, de asemenea, apeluri de funcții încorporate într-un obiect sau clasă (adesea numite apeluri de metodă ); unele permit chiar migrarea tipurilor de date complexe și / sau a obiectelor peste granița limbii.
În majoritatea cazurilor, un FFI este definit de un limbaj „de nivel superior”, astfel încât acesta poate folosi servicii definite și implementate într-un limbaj de nivel inferior, de obicei un limbaj de sistem precum C sau C ++ . Acest lucru se face în mod obișnuit fie pentru a accesa serviciile sistemului de operare în limba în care este definit API-ul OS, fie pentru considerente de performanță.
Multe FFI oferă, de asemenea, mijloacele pentru ca limba apelată să invoce servicii și în limba gazdă.
Termenul de interfață funcție străină nu este, în general, folosit pentru a descrie timpii de execuție multi-lingvistici, cum ar fi Microsoft Common Language Runtime , unde este furnizat un „substrat” comun care permite oricărui limbaj compatibil CLR să utilizeze servicii definite în oricare altul. (Cu toate acestea, în acest caz, CLR include un FFI, P / Invoke , pentru a apela în afara runtime-ului.) În plus, multe arhitecturi de calcul distribuite, cum ar fi invocarea metodelor la distanță Java (RMI), RPC, CORBA , SOAP și D- Autobuzul permite scrierea diferitelor servicii în diferite limbi; astfel de arhitecturi nu sunt în general considerate FFI.
Cazuri speciale
Există câteva cazuri speciale, în care limbajele se compilează în același bytecode VM, cum ar fi Clojure și Java , precum și Elixir și Erlang . Deoarece nu există o interfață, nu este un FFI, strict vorbind, în timp ce oferă utilizatorului aceeași funcționalitate.
Vezi si
- Interoperabilitatea limbajului
- Limbajul de definire a interfeței
- Convocarea apelului
- Denumiți mangling
- Interfața de programare a aplicației
- Interfață binară a aplicației
- Compararea mașinilor virtuale de aplicații
- ÎNGHIŢITURĂ
- Apel procedură la distanță
- libffi
Referințe
linkuri externe
- c2.com: Interfață funcție străină
- Interfața funcției străine Haskell 98
- Allegro Common Lisp FFI
- Un generator de interfață de funcții străine pentru occam-pi
- UFFI: interfață funcție externă universală Lisp
- CFFI: Interfață funcție străină comună, pentru Common Lisp
- Interfață nativă Java: Ghid și specificații ale programatorului
- Specificația JNI
- JSNI (JavaScript Native Interface)
- biblioteca dyncall folosind nuclee de apeluri de asamblare pentru o varietate de procesoare, sisteme de operare și convenții de apelare
- FFCALL
- C / Invocă
- libffi