อยากตอบคำถามง่ายๆ... FFI ใน Ruby คืออะไร?
FFI = "Foreign Function Interface" — ทาง ใช้ Functions ที่ Define ในภาษาอื่น
Ruby's FFI Module ให้ Access External Libraries และ Code ที่ไม่ได้มีอยู่
มัก用กับ C Code — ตัวอย่าง: rb-inotify, ruby-vips, ruby-nfc
เขียนโปรแกรม用 FFI เองได้ด้วย FFI Module — มาดู Code Examples!
FFI Basics: Loading & Importing Functions
用 FFI โดย Include Functions เข้า Module ที่สร้าง
แบบนี้:
require 'ffi' module A extend FFI::Library end
ใน Module โหลด Library ด้วย ffi_lib — C Library (DLL ใน Windows, SO ใน Linux) Export "Symbols" (Function Definitions)
Require "libc" (C Standard Library) — ทำแบบนี้:
module A extend FFI::Library ffi_lib 'c' end
ตอนนี้: Import Specific Functions จาก Library เป็น Ruby Methods — ด้วย attach_function
ตัวอย่าง:
module A
extend FFI::Library
ffi_lib 'c'
attach_function :strlen, [:string], :int
end
A.strlen("abc") # 3
ทำงานยังไง? รู้ว่า C มี Function strlen รับ chars * -> String ใน Ruby — คืนความยาว String
attach_function รับ 3 Parameters:
- ชื่อ C Function
- Array ของ Argument Types
- Return Type
ต้องอ่าน Documentation หา Types ของ Function นั้น — มาตัวอย่างต่อไป!
สร้าง Media Player เอง
Libraries น่าสนใจเยอะ — Linux อยู่ /usr/lib/ เริ่ม lib จบ .so
List แบบนี้: ls /usr/lib/lib*.so
ตัวนี้用 VLC Media Player Library: /usr/lib/libvlc.so
เป้าหมาย: โหลด MP3 และ Play!
เริ่มต้น:
require 'ffi' module VLC extend FFI::Library ffi_lib 'vlc' attach_function :libvlc_get_version, [], :string end
Test Library Load ถูกต้อง Print Version — แบบนี้:
VLC.libvlc_get_version # "3.0.6 Vetinari"
ตั้งชื่อ Method เองได้ด้วย Parameter ที่ 4 — attach_function :get_version, :libvlc_get_version, [], :string
แล้ว: VLC.get_version
Play MP3 ต้องอะไร? Doc: libvlc_media_player_play ดูแล้ว — ต้องการ Media Player "Object"
Media Player ต้อง Media, Media ต้อง VLC Instance — Process:
VLC Instance -> Media -> Media Player -> Play
ประกอบจาก Doc libVLC
Memory Pointers ใน Ruby???
C ไม่มี Objects ทุกอย่าง用 Memory Pointers — Memory Address พร้อม Data
Code Example:
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
เรียก VLC.new ได้ Pointer — ส่งต่อให้ C Functions อื่นที่ต้องการ
ตอนนี้: Full Example และวิธีใช้
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
พอเล่นเพลงแล้ว:
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)
เล่นเพลงโดยไม่เปิด Visual Interface — สร้าง Web Interface บนนี้ได้ — ลองดูสิ!
Summary (สรุป)
คุณเรียนรู้พลัง FFI! Ruby Module ใช้ External Libraries 象 Part ของภาษาเอง
Share บทความให้เพื่อนเพลิดเพลิน 🙂 — ขอบคุณที่อ่านครับ!