Tôi muốn trả lời một câu hỏi đơn giản... FFI trong Ruby là gì? FFI = "Foreign Function Interface". Cách dùng hàm định nghĩa trong ngôn ngữ lập trình khác. Module FFI Ruby cho truy cập thư viện & code bên ngoài bạn không có cách khác. Thường dùng làm việc với C code. Ví dụ: rb-inotify, ruby-vips, ruby-nfc. Bạn viết chương trình dùng FFI với giúp module FFI. Làm sao? Xem vài ví dụ code!
FFI Basics: Load & Import Functions
Làm việc FFI bằng include functions vào module bạn tạo. Như:
require 'ffi' module A extend FFI::Library end
Bên trong module, load library dùng ffi_lib. Thư viện C, như "DLL" Windows, hoặc "SO" Linux, export danh sách "symbols", hoặc định nghĩa hàm chương trình làm available cho người khác dùng. Require "libc", thư viện chuẩn C. Cách:
module A extend FFI::Library ffi_lib 'c' end
Bây giờ: Import hàm cụ thể từ library này như Ruby method. Với attach_function. Ví dụ:
module A
extend FFI::Library
ffi_lib 'c'
attach_function :strlen, [:string], :int
end
A.strlen("abc") # 3
Cơ chế: Biết có hàm C tên strlen, nhận chars * argument. chars * dịch sang String Ruby. Hàm strlen trả về độ dài string. attach_function nhận 3 tham số: 1. Tên hàm C 2. Mảng kiểu argument 3. Kiểu trả về. Phải đọc doc tìm kiểu hàm cụ thể dùng. Ví dụ khác!
Xây Dựng Media Player Của Riêng Bạn
Tìm nhiều library thú vị. Linux, phần lớn dưới /usr/lib/, tên bắt đầu "lib" & kết thúc "so". Liệt kê: ls /usr/lib/lib*.so. Ví dụ này dùng thư viện media player VLC: /usr/lib/libvlc.so. Mục tiêu: load mp3 & play! Bắt đầu:
require 'ffi' module VLC extend FFI::Library ffi_lib 'vlc' attach_function :libvlc_get_version, [], :string end
Test library load đúng & in version. Như: VLC.libvlc_get_version # "3.0.6 Vetinari". Đặt tên custom cho method bằng tham số 4. Ví dụ: attach_function :get_version, :libvlc_get_version, [], :string. Rồi VLC.get_version. Cần gì để play mp3? Xem doc, libvlc_media_player_play trông như cách. Hàm này cần media player "object". Media player cần media, media cần VLC instance. Quy trình: VLC instance -> media -> media_player -> play. Tôi ghép từ doc libVLC.
Con Trỏ Bộ Nhớ Trong Ruby???
Trong C không tìm object, mọi thứ dùng con trỏ bộ nhớ. Con trỏ = địa chỉ bộ nhớ có data. Xem code:
module VLC extend FFI::Library ffi_lib 'vlc' attach_function :get_version, :libvlc_get_version, [], :string attach_function :new, :libvlc_new, [:int, :int], :pointer end VLC.new(0, 0) # FFI::Pointer address=0x000055c6f04ae7b0
Kết quả VLC.new là con trỏ. Phải pass cho hàm C khác cần nó. Bây giờ: Ví dụ đầy đủ & cách dùng.
module VLC extend FFI::Library ffi_lib 'vlc' attach_function :version, :libvlc_get_version, [], :string attach_function :new, :libvlc_new, [:int, :int], :pointer attach_function :libvlc_media_new_path, [:pointer, :string], :pointer attach_function :libvlc_media_player_new_from_media, [:pointer], :pointer attach_function :play, :libvlc_media_player_play, [:pointer], :int attach_function :stop, :libvlc_media_player_stop, [:pointer], :int attach_function :pause, :libvlc_media_player_pause, [:pointer], :int end
Đủ chơi nhạc:
vlc = VLC.new(0, 0) media = VLC.libvlc_media_new_path(vlc, "/home/jesus/Downloads/meditation.mp3") player = VLC.libvlc_media_player_new_from_media(media) VLC.play(player)Phát nhạc, không mở giao diện visual. Có thể build web interface trên này. Thử đi!
Tóm Tắt
Bạn đã học sức mạnh tuyệt vời của FFI! Module Ruby cho phép dùng thư viện bên ngoài như thể chúng là phần của ngôn ngữ. Hãy chia sẻ để nhiều người tận hưởng 🙂 Cảm ơn bạn đã đọc!