FFI — bir dasturlash tilida yozilgan kodga boshqa til yoki binary interfeysda yaratilgan funksiya va kutubxonalarni chaqirish imkonini beradigan mexanizm. Uning to‘liq nomi Foreign Function Interface hisoblanadi.
FFI yordamida yuqori darajali til operatsion tizim APIlari, C kutubxonalari, qurilma drayverlari, ilmiy hisoblash paketlari yoki avvaldan mavjud native kod bilan ishlaydi.
Asosiy vazifa
Dasturlash tillari xotira, type, exception va function callni turlicha boshqaradi. FFI shu farqlar orasida ko‘prik vazifasini bajaradi.
U quyidagilarni belgilashi kerak:
- function nomi;
- calling convention;
- argument type’lari;
- return type;
- structure layout;
- pointer;
- string encoding;
- memory ownership;
- error qaytarish;
- callback;
- thread qoidalari.
Eng kichik mos kelmaslik ham noto‘g‘ri natija yoki process crashiga olib kelishi mumkin.
C ABI
Ko‘p FFI tizimlari C ABI’ni umumiy chegara sifatida tanlaydi.
Buning sabablari:
- C calling convention sodda;
- ko‘p platformada barqaror;
- boshqa tillar C-compatible function eksport qila oladi;
- system librarylar ko‘pincha C API beradi;
- name mangling kamroq murakkab.
C++ class, template va exceptionni bevosita eksport qilishdan ko‘ra, ularning ustiga C wrapper yozish keng tarqalgan.
Function chaqirish
C kutubxonasida quyidagi funksiya bo‘lsin:
int add(int a, int b);
FFI deklaratsiyasi boshqa tilda shu functionning binary signature’ini ifodalaydi.
- libraryni yuklaydi;
addsymbolini topadi;- argumentlarni ABIga mos register yoki stackka joylaydi;
- native functionga o‘tadi;
- return qiymatini tilning ichki type’iga aylantiradi.
Dynamic library yuklash
FFI libraryni runtime’da yuklashi mumkin.
Platformaga qarab:
.so;.dll;.dylib
formatlari ishlatiladi.
Loader library path, architecture va dependencylarni tekshiradi.
Library topilmasa yoki kerakli symbol eksport qilinmagan bo‘lsa, FFI chaqiruvi boshlanmaydi.
Type mapping
Har til type’lari C type’lariga bir xil mos kelmaydi.
Masalan:
inthajmi platformaga bog‘liq;- boolean representation farq qilishi mumkin;
- string obyekt va null-terminated
char*bir xil emas; - enum width farq qiladi;
- managed object pointerini native kod to‘g‘ridan-to‘g‘ri tushunmaydi.
Fixed-width type, masalan int32_t, binary interfeysni aniqroq qiladi.
String
String FFI’da eng ko‘p xato beradigan obyektlardan biri.
Aniqlanishi kerak:
- UTF‑8, UTF‑16 yoki boshqa encoding;
- null terminator;
- uzunlik alohida beriladimi;
- buffer kimga tegishli;
- native function stringni o‘zgartiradimi;
- natijani kim bo‘shatadi.
String ichida nol bayt bo‘lsa, null-terminated C API uni erta tugagan deb qabul qilishi mumkin.
Structure
Structure field tartibi, alignment va padding ABIga mos bo‘lishi kerak.
Misol:
struct Point {
int32_t x;
int32_t y;
};
FFI tomonda fieldlar boshqa tartib yoki boshqa width bilan e’lon qilinsa, native kod noto‘g‘ri qiymat o‘qiydi.
Packed structure ishlatilsa, alignment va performance oqibatlari hisobga olinadi.
Pointer
Pointer native memory manzilini bildiradi.
FFI orqali pointer bilan ishlashda:
- null;
- lifetime;
- mutability;
- alignment;
- buffer length;
- dangling pointer
nazorat qilinadi.
Managed runtime garbage collector objectni ko‘chirishi mumkin. Native kod ishlatayotgan paytda object pinned qilinishi yoki alohida native bufferga nusxalanishi mumkin.
Memory ownership
Kim xotira ajratgani va kim bo‘shatishi aniq belgilanadi.
Misollar:
- caller buffer beradi;
- callee yangi buffer qaytaradi;
- maxsus
free_result()function mavjud; - natija keyingi chaqiriqqacha amal qiladi;
- reference counting ishlatiladi.
Bir allocator ajratgan blokni boshqa runtime allocatorida bo‘shatish heap corruptionga sabab bo‘lishi mumkin.
Callback
Native library boshqa tildagi functionni keyinroq chaqirishi mumkin. Bu callback hisoblanadi.
FFI callback uchun:
ni boshqaradi.
Callback garbage collector tomonidan yig‘ilib qolmasligi uchun reference saqlanadi.
Thread
Native library callbackni o‘zi yaratgan threaddan chaqirishi mumkin.
Managed runtime threaddan xabardor bo‘lmasa:
- runtime attach;
- interpreter lock;
- thread-local context;
- event loop dispatch
talab qilinadi.
GUI callbackini background native threaddan to‘g‘ridan-to‘g‘ri chaqirish xavfli bo‘lishi mumkin.
Exception
Bir til exceptionini boshqa ABI chegarasidan nazoratsiz o‘tkazish mumkin emas.
C wrapper odatda exceptionni ushlab:
- error code;
- null;
- status structure;
- thread-local error
ko‘rinishida qaytaradi.
Native function ichidan managed runtime exceptioni chiqib ketsa stack unwinding mos kelmasligi mumkin.
Error modeli
C API ko‘pincha:
- return code;
errno;- output parameter;
- error object
ishlatadi.
FFI wrapper bu xatoni target til exception yoki result type’iga aylantiradi.
errno qiymati keyingi system call bilan o‘zgarishi mumkin, shuning uchun darhol olinadi.
Performance
FFI boundary’da:
- argument conversion;
- string nusxalash;
- memory pinning;
- runtime transition;
- callback;
- lock
overhead mavjud.
Kichik amalni million marta alohida chaqirishdan ko‘ra, katta batch bilan chaqirish samaraliroq.
Binding generator
Header yoki interface description asosida FFI binding avtomatik yaratilishi mumkin.
Vosita:
- function declaration;
- constant;
- structure;
- enum;
- documentation
ni target tilga aylantiradi.
Generated binding ham library versiyasi va ABI bilan mos bo‘lishi kerak.
Xavfsizlik
FFI memory-safe tilning himoya chegarasini zaiflashtiradi.
Native kod:
keltirib chiqarishi mumkin.
FFI wrapper input uzunligi va ownershipni qat’iy tekshiradi.
Diagnostika
FFI muammosida:
- architecture;
- library path;
- exported symbol;
- calling convention;
- type width;
- structure layout;
- string encoding;
- memory ownership;
- callback lifetime;
- thread;
- native debugger
tekshiriladi.
Tasodifiy crash ko‘pincha chaqiriqdan oldingi noto‘g‘ri declaration yoki xotira umri bilan bog‘liq bo‘ladi.
Bog‘liq tushunchalar
ABI, C API, Dynamic library, Calling convention, Pointer, Memory ownership, Callback, Native code, Binding, Marshaling