سلام گاهی پیش میاد که نیاز داشته باشید از زبان های دیگه در برنامه استفاده کنید. تو این پست میخوام یه مقدمه از ffi (foreign function interface) در nodejs ارایٔه دهم.
بهطور کلی، FFI مکانیزمی است که به وسیله آن برنامهای که با یک زبان برنامهنویسی نوشته شده است، میتواند از روتینها و خدماتی که با زبان دیگری نوشته یا کامپایل شدهاند، استفاده کند.
میتوانید از تعریف ویکیپدیا برای این موضوع استفاده کنید:
A foreign function interface (FFI) is a mechanism by which a program written in one programming language can call routines or make use of services written or compiled in another one.
(wikipedia :منبع)
فرض کنید یک عملیات سنگین را نیاز دارید که بهتر است از زبان Rust به جای Node.js استفاده کنید تا بهبود عملکرد برنامهتان را تجربه کنید. به عنوان مثال، فرض کنید محاسبهی دنباله فیبوناچی را با استفاده از Rust انجام داده و خروجی را در Node.js دریافت کنید.
اجازه دهید با یک مثال این موضوع را بهتر درک کنید. در محیط ترمینال دستورات زیر را وارد کنید:
$ mkdir my_ffi $ cd my_ffi $ cargo new rust_app # ساخت پروژه با rust $ cd rust_app $ mkdir ./src/math $ touch lib.rs
تا اینجا، یک دایرکتوری به نام my_ffi
ساخته شده است و داخل آن یک پروژه Rust با دستور cargo new rust_app
ساخته شده است. سپس، یک ماژول به نام math
در مسیر src/math
ایجاد شده است. همچنین، نیاز است که در فایل Cargo.toml
تعریف کنیم که این ماژول مورد استفاده قرار بگیرد.
[package] name = "rust_app" version = "0.1.0" edition = "2021" # این چهار خط را اضافه کنید [lib] name = "math" path = "./src/math/lib.rs" crate-type=["rlib","cdylib"] [dependencies]
مرحله تعریف ماژول به پایان رسید. اما نیاز است که توضیحی کوچک درباره crate-type = ["rlib", "cdylib"]
بدهم.
خلاصهاش این است که این خط نوع کتابخانه تولید شده را تعیین میکند. rlib
به معنی این است که یک کتابخانه Rust استاتیک تولید شده است و cdylib
به معنی این است که یک کتابخانه Rust پویا است و میتوانید از آن در زبانهایی مانند C، C#، Java، JavaScript و غیره استفاده کنید. برای درک بهتر، لینک مرجع را مطالعه کنید.
حالا نوبت به فایل src/math/lib.rs
میرسد. کد زیر را بنویسید:
#[no_mangle] pub extern "C" fn fib(number: i32) -> i32 { if number == 0 { return 0; } else if number == 1 { return 1; } else { return fib(number - 1) + fib(number - 2); } }
در این قسمت، تابع محاسبهی دنباله فیبوناچی را نوشتهایم. قبل از ادامه، توضیح کوچکی درباره برخی کلمات کلیدی در کد ضروری است.
pub
: به این معنی است که از این تابع میتوان در ماژولهای دیگر استفاده کرد.extern
: این کلیدواژه به این معنی است که میتوان از این تابع در خارج از برنامه نیز استفاده کرد.#[no_mangle]
: به طور کلی به کامپایلر Rust میگوید نام این تابع را تغییر ندهد.حالا کدهای Rust به پایان رسیدهاند و در نهایتنیاز است که یک نسخهی Release از آن بسازیم. برای این کار، دستور زیر را در ترمینال اجرا کنید:
$ cargo build --release
در نهایت، یک فایل Release در دایرکتوری target
ساخته شده است.
حالا به بخش Node.js میرویم. دستورات زیر را برای ساخت یک پروژه Node.js وارد ترمینال کنید:
$ cd .. $ mkdir node_app $ cd node_app $ npm init -y $ npm i ffi-napi # نصب ffi-napi $ touch index.js # ساخت فایل index.js
سپس، در فایل package.json
، قسمت scripts
را به صورت زیر ویرایش کنید:
"scripts": { "start": "node index.js" }
در انتها، کد JavaScript را بنویسید و از Rust استفاده کنید:
const ffi = require("ffi-napi"); // مسیر لایبری که میخوایم استفاده کینم // نیازی به وارد کردن پسوند نیست const libPath = "../rust_app/target/release/libmath" const math = ffi.Library(path, { // <function_name>: [ "<return_value_type>": ["<argType>"] ] fib: ["int", ["int"]], }); const result = math.fib(45); console.log(result);
و تمام!