דלג לתוכן הראשי

FFI

מסמך זה מתאר את המפרט של FFI (ממשק פונקציות חיצוני) לצורך קריאה לפונקציות המוטמעות חיצונית בשפת Wave. באמצעות FFI, תכנית Wave יכולה להשתלב ישירות עם ספריות מקומיות שנכתבו בשפות אחרות.


סקירה כללית

ה-FFI של Wave פועל על בסיס הכרזות. הפונקציה החיצונית אינה מיושמת בקוד של Wave, אלא רק מציינת את ה-ABI (ממשק בינארי יישומי) שהיא עוקבת אחריו. היישום בפועל נפתר בשלב הקישור על ידי ספריה חיצונית.

FFI מכריזה על קיום הפונקציה בזמן ההידור, ובזמן יצירת קובץ הפעלה, הקישור מבצע חיבור סמלים בפועל.


הכרזת extern

הפונקציה החיצונית מוכרזת באמצעות מילת המפתח extern. נכון לעכשיו, ב-Wave יש צורך לציין ABI ותומכים רק ב-extern(c).

extern(c) fun שם פונקציה(פרמטרים...) -> סוג החזרה;

קביעת ABI

בהכרזת extern יש צורך לציין ABI. כרגע תומכים ב-ABI אחד בלבד שהוא c.

extern(c) fun printf(fmt: ptr<u8>);

הכרזה כמו extern(rust) יכולה לנתח אך תגרום לשגיאה בשלב ניתוח המשמעות.


הכרזת extern ברמת הפונקציה

כאשר מצהירים על פונקציה חיצונית אחת, כותבים זאת כך.

extern(c) fun InitWindow(width: i32, height: i32, title: ptr<u8>);

ההצהרה הזו מציינת כי הסימבול InitWindow העוקב אחרי ABI של C קיים בספריה חיצונית.


הכרזת extern ברמת בלוק

כאשר יש מספר פונקציות חיצוניות המשתמשות באותו ABI, ניתן לקבץ אותן בהכרזה בצורת בלוק.

extern(c) {
fun InitWindow(width: i32, height: i32, title: ptr<u8>);
fun CloseWindow();
fun BeginDrawing();
fun EndDrawing();
}

ההכרזה ברמת בלוק היא זהה מבחינה משמעותית להכרזה ברמת פונקציה, ומשתמשים בה רק לגודליות ולמבנה.


הגדרת שם סימבול

בחלק מה-ABI, יתכן כי שם הפונקציה ב-Wave וסימבול הלינקר האמיתי אינם זהים. במקרה הזה, ניתן לציין את שם הסימבול האמיתי שהפונקציה החיצונית תקושר אליו כמחרוזת.

הגדרת סימבול ברמת פונקציה

extern(c, "puts")
fun rust_func(i32);

ההצהרה הזו קובעת שבקריאה ל-rust_func, יש להשתמש בסימבול הלינק puts.


הגדרת סימבול ברמת בלוק

בהכרזה ברמת בלוק, ניתן להגדיר שם סימבול בנפרד אחרי כל פונקציה.

extern(c) {
fun my_puts(ptr<i8>) "puts";
fun my_strlen(ptr<i8>) "strlen";
}

סוג מצביע

מצביע מתבטא בצורת ptr<T>.

ptr<u8>
ptr<MyStruct>

ה-ptr<T> תואם באופן ישיר למצביע בשפה חיצונית, ו-Wave אינו מנהל את הבעלות על הזיכרון או אורך החיים.


שימוש במבנה

ניתן להשתמש במבנה כפרמטר או ערך חזרה של פונקציה חיצונית.

struct Color {
r: u8,
g: u8,
b: u8,
a: u8,
}

כאשר משתמשים במבנה ב-FFI, סדר השדות נשמר כפי שהוצהר והוא עוקב אחרי הסידור הזיכרון הנדרש ב-ABI.


קריאת פונקציה חיצונית

פונקציה שהוכרזה כ-extern נקראת באותו אופן כמו פונקציה רגילה.

fun main() -> i32 {
InitWindow(800, 600, "Wave");
BeginDrawing();
EndDrawing();
CloseWindow();
return 0;
}

אין הבדלים תחביריים בקריאה, והנורמות הקריאה וסימבול הלינקר מנוהלים במלואם על ידי ה-ABI והלינקר.


קישור

היישום האמיתי של פונקציה חיצונית מסופק בשלב הקישור על ידי ספריה חיצונית. מהדר ה-Wave יוצר קובץ אובייקט הכולל קריאות לפונקציה חיצונית, והלינקר פותר את הסימבולים דרך הספריה שצוינה.

אופן ציון הספריה מתבצע דרך כלי הבניה ואפשרויות ה-CLI.


הגבלות

Wave אינו מספק את הפונקציות הבאות.

  • מצביע פונקציה
  • פונקציית callback
  • ניהול זיכרון אוטומטי
  • שילוב טיפול יוצאים בין שפות

ייתכן שהפונקציות האלה יטופלו בנפרד בגרסאות עתידיות.