מחוללי מקורות

הדף הזה מספק תצוגה ברמה גבוהה של התמיכה במקור שנוצר ואיך אפשר להשתמש בו במערכת ה-build.

כל הגנרטורים של מקורות מספקים פונקציונליות דומה של מערכת build. שלושת תרחישי השימוש ליצירת מקורות שנתמכים במערכת ה-build יוצרים קישורי C באמצעות bindgen, ממשקי AIDL וממשקי protobuf.

ארגזים מהמקור שנוצר

אפשר להשתמש בכל מודול Rust שיוצר קוד מקור כ-crate, בדיוק כמו שהוא מוגדר כ-rust_library. (כלומר, אפשר להגדיר אותו כיחס תלות במאפיינים rustlibs, ‏ rlibs ו-dylibs). דפוס השימוש הטוב ביותר בקוד פלטפורמה הוא להשתמש במקור שנוצר כ-crate. למרות שהמאקרו include! נתמך במקור שנוצר, המטרה העיקרית שלו היא לתמוך בקוד של צד שלישי שנמצא ב-external/.

יש מקרים שבהם קוד הפלטפורמה עדיין ישתמש במקור שנוצר באמצעות המאקרו include!(), למשל אם משתמשים במודול genrule כדי ליצור מקור באופן ייחודי.

שימוש ב-include!() כדי לכלול מקור שנוצר

הדוגמאות לדף של כל מודול ספציפי (מתאים) כוללות הסבר על שימוש במקור שנוצר כ-crate. בקטע הזה מוסבר איך להפנות למקור שנוצר באמצעות המאקרו include!(). חשוב לזכור שהתהליך הזה דומה לכל הגנרטורים של מקורות הנתונים.

דרישה מוקדמת

הדוגמה הזו מבוססת על ההנחה שהגדרתם מודול rust_bindgen (libbuzz_bindgen) ואפשר להמשיך לשלבים להכללת מקור שנוצר כדי להשתמש במאקרו include!(). אם לא עשיתם זאת, היכנסו למאמר הגדרת מודול קישור חלודה, צרו libbuzz_bindgen וחזרו לכאן.

חשוב לשים לב שהחלקים של קובצי ה-build האלה רלוונטיים לכל מחוללי המקור.

שלבים להכללת המקור שנוצר

יוצרים את הקובץ external/rust/hello_bindgen/Android.bp עם התוכן הבא:

rust_binary {
   name: "hello_bzip_bindgen_include",
   srcs: [
         // The primary rust source file must come first in this list.
         "src/lib.rs",

         // The module providing the bindgen bindings is
         // included in srcs prepended by ":".
         ":libbuzz_bindgen",
    ],

    // Dependencies need to be redeclared when generated source is used via srcs.
    shared_libs: [
        "libbuzz",
    ],
}

יוצרים את הקובץ external/rust/hello_bindgen/src/bindings.rs עם התוכן הבא:

#![allow(clippy::all)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(unused)]
#![allow(missing_docs)]

// Note that "bzip_bindings.rs" here must match the source_stem property from
// the rust_bindgen module.
include!(concat!(env!("OUT_DIR"), "/bzip_bindings.rs"));

יוצרים את הקובץ external/rust/hello_bindgen/src/lib.rs עם התוכן הבא:

mod bindings;

fn main() {
    let mut x = bindings::foo { x: 2 };
    unsafe { bindings::fizz(1, &mut x as *mut bindings::foo) }
}

למה כדאי להשתמש בקונטיינרים לקוד מקור שנוצר

בניגוד למהדרים של C/C++, rustc מקבל רק קובץ מקור אחד שמייצג נקודת כניסה לקובץ בינארי או לספרייה. המערכת מצפה שהמבנה של עץ המקור יהיה כזה שאפשר יהיה למצוא בו באופן אוטומטי את כל קובצי המקור הנדרשים. כלומר, צריך למקם את המקור שנוצר בעץ המקור, או לספק אותו באמצעות הוראה של include במקור:

include!("/path/to/hello.rs");

קהילת Rust מסתמכת על סקריפטים של build.rs ועל הנחות לגבי סביבת ה-build של Cargo כדי לפתור את ההבדל הזה. במהלך ה-build, הפקודה cargo מגדירה משתנה סביבה OUT_DIR, שאליו סקריפטים של build.rs אמורים להציב את קוד המקור שנוצר. משתמשים בפקודה הבאה כדי לכלול את קוד המקור:

include!(concat!(env!("OUT_DIR"), "/hello.rs"));

זהו אתגר עבור Soong, כי הפלט של כל מודול ממוקם בספריית out/ משלו1. אין OUT_DIR יחיד שבו יחסי התלות מניבים את המקור שנוצר.

בקוד פלטפורמה, ב-AOSP מעדיפים לארוז את המקור שנוצר בקונטיינר שאפשר לייבא, מכמה סיבות:

  • למנוע התנגשויות בשמות של קובצי המקור שנוצרו.
  • צמצום קוד סטנדרטי שמאושר לאורך העץ ודורש תחזוקה. אפשר לנהל באופן מרכזי כל קוד תבנית שנדרש כדי לעבד את המקור שנוצר ל-crate.
  • הימנעו מאינטראקציות מרומזות2 בין הקוד שנוצר לבין ה-crate שמקיף אותו.
  • קישור דינמי של מקורות שנוצרו ונמצאים בשימוש נפוץ כדי להפחית את הלחץ על הזיכרון והדיסק.

כתוצאה מכך, כל סוגי המודולים ליצירת קוד מקור ב-Rust ב-Android יוצרים קוד שאפשר לקמפל ולהשתמש בו כ-crate. Soong עדיין תומך ב-crates של צד שלישי ללא שינוי, אם כל יחסי התלות של המקור שנוצרו למודול מועתקים לספרייה אחת לכל מודול, בדומה ל-Cargo. במקרים כאלה, Soong מגדיר את משתנה הסביבה OUT_DIR לספרייה הזו בזמן הידור המודול, כדי שאפשר יהיה למצוא את המקור שנוצר. עם זאת, מהסיבות שצוינו קודם מומלץ להשתמש במנגנון הזה רק בקוד הפלטפורמה כאשר הוא הכרחי.


  1. אין בעיה עם שפות C/C++ ושפות דומות, כי הנתיב למקור שנוצר מסופק ישירות למהדר. 

  2. מכיוון ש-include! פועלת על ידי הכללה טקסטואלית, היא עשויה להפנות לערכים ממרחב השמות המקיף, לשנות את מרחב השמות או להשתמש במבנים כמו #![foo]. קשה לנהל אינטראקציות מרומזות כאלה. תמיד עדיף להשתמש במאקרו כשיש צורך אמיתי באינטראקציה עם שאר ה-crate.