Стендап Сьогодні 📢 Канал в Telegram @stendap_sogodni
🤖🚫 AI-free content. This post is 100% written by a human, as is everything on my blog. Enjoy!29.01.2024
Вбудовування бінарної бібліотеки в Ruby - словничок
Викликати бінарний код з Ruby - це настільки нормально, що стандартна бібліотека робить це щосекунди. На те є стандартний механізм інтеграції, який починається з ruby.h. Це заголовок C. На цей час С є спільною фундацією майже для всіх компільованих мов, тож будь то Go, Crystal, чи навіть асемблер, все одно буде інтегруватись через C.
Щоб зінтегруватись, ми повинні збудувати shared library, або ж як їх знають на Windows, DLL. При цьому ми підʼєднаємо до нашої бібліотеки “адаптер” до самого Ruby; на то є модуль mkmf. Сама бібліотека може бути написана будь-якою мовою, яка вміє створювати shared library.
Далі — у бібліотеці ми оголошуємо клас чи модуль: rb_define_module та наповнюємо його. А в Ruby - просто робимо бібліотеці require
, та навіть нічого не треба знати про те, що вона зовнішня. Магія!
Втім, за досвідом, саме код інтеграції, який ховається за цією магією, буде найнеприємнішим. По-перше, він має бути написаний на C (або тонкій абстракції над C - такій, як CGO). По-друге, і це ще не все, бо доведеться конвертувати типи в спеціальні для Ruby та робити інші цікаві речі.
Щоб уникнути такого коду, я знаю два інструменти. SWIG - це генератор коду інтеграції з заголовків C. Тобто достатньо зробити звичайну бібліотеку без інтеграції з Ruby. Або навіть взяти чужу - 14 років тому я так загортав glew - бібліотеку доповнень до OpenGL: SWIG особливо гарний для інтеграції великих чужих бібліотек.
А FFI то вже модуль для Ruby, який здатний зінтегрувати готову динамічну бібліотеку. Робить він це через власний шар C, який ми метапрограмуємо з Ruby. Тому FFI буде повільніше, ніж SWIG чи пряма інтеграція. Хоча це буде помітно тільки на коротких та частих викликах. FFI має сенс брати там, де лізти в вихідний код бібліотеки не можна або не хочеться.