בדף הזה מוסבר איך המערכת תומכת בקוד מקור שנוצר ואיך אפשר להשתמש בו במערכת הבנייה.
כל מחוללי המקור מספקים פונקציונליות דומה של מערכת בנייה. שלושת תרחישי השימוש הנתמכים במערכת הבנייה ליצירת קוד מקור הם יצירת קשרי C באמצעות bindgen, ממשקי AIDL וממשקי protobuf.
ארגזים ממקור שנוצר
אפשר להשתמש בכל מודול Rust שיוצר קוד מקור כחבילת crate, בדיוק כמו אם הוא הוגדר כ-rust_library
. (כלומר, אפשר להגדיר אותו כתלות במאפיינים rustlibs
, rlibs
ו-dylibs
). הדרך הכי טובה להשתמש בקוד של הפלטפורמה היא להשתמש במקור שנוצר כ-crate. למרות שיש תמיכה בפקודת המאקרו include!
בקוד המקור שנוצר, המטרה העיקרית שלה היא לתמוך בקוד של צד שלישי שנמצא ב-external/
.
יש מקרים שבהם קוד הפלטפורמה עדיין עשוי להשתמש במקור שנוצר באמצעות המאקרו include!()
, למשל כשמשתמשים במודול genrule
כדי ליצור מקור בצורה ייחודית.
שימוש בפונקציה include!() כדי לכלול מקור שנוצר
השימוש במקור שנוצר כחבילת crate מוסבר בדוגמאות בכל דף מודול ספציפי (רלוונטי). בקטע הזה מוסבר איך להפנות למקור שנוצר באמצעות מאקרו include!()
. שימו לב שהתהליך הזה דומה לכל הגנרטורים של מקורות.
דרישה מוקדמת
הדוגמה הזו מבוססת על ההנחה שהגדרתם מודול rust_bindgen
(libbuzz_bindgen
) ואפשר להמשיך אל השלבים להכללת מקור שנוצר כדי להשתמש בפקודת המאקרו include!()
. אם לא עשיתם את זה, אתם צריכים לעבור אל הגדרת מודול rust bindgen, ליצור libbuzz_bindgen
ואז לחזור לכאן.
שימו לב שהחלקים בקובץ הבנייה רלוונטיים לכל מחוללי המקור.
איך לכלול מקור שנוצר
יוצרים את הקובץ 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) }
}
למה כדאי להשתמש ב-crates לקוד מקור שנוצר
בניגוד לקומפיילרים של 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 שאפשר לייבא, מכמה סיבות:
- למנוע התנגשות בין שמות של קובצי מקור שנוצרו.
- צמצום קוד סטנדרטי שנבדק בכל העץ ודורש תחזוקה. אפשר לנהל באופן מרכזי כל תבנית קבועה שנדרשת כדי לקמפל את המקור שנוצר ל-crate.
- מומלץ להימנע מאינטראקציות מרומזות2 בין קוד שנוצר לבין ה-crate שמסביב.
- כדי להפחית את העומס על הזיכרון ועל הדיסק, אפשר לקשר באופן דינמי מקורות שנוצרו בדרך כלל.
כתוצאה מכך, כל סוגי המודולים ליצירת קוד המקור של Rust ב-Android יוצרים קוד שאפשר לקמפל ולהשתמש בו כחבילת crate.
Soong עדיין תומך ב-crates של צד שלישי ללא שינוי, אם כל התלויות בקוד המקור שנוצרות עבור מודול מועתקות לספרייה אחת לכל מודול, בדומה ל-Cargo. במקרים כאלה, מערכת Soong מגדירה את משתנה הסביבה OUT_DIR
לספרייה הזו בזמן הידור המודול, כדי שיהיה אפשר למצוא את קובץ המקור שנוצר.
עם זאת, מהסיבות שכבר תוארו, מומלץ להשתמש במנגנון הזה בקוד של הפלטפורמה רק כשאין ברירה אחרת.
-
הדבר לא יוצר בעיות בשפות C/C++ ובשפות דומות, כי הנתיב למקור שנוצר מסופק ישירות לקומפיילר. ↩
-
הפונקציה
include!
פועלת על ידי הכללה של טקסט, ולכן היא עשויה להפנות לערכים ממרחב השמות המקיף, לשנות את מרחב השמות או להשתמש במבנים כמו#![foo]
. יכול להיות שיהיה קשה לשמור על האינטראקציות המרומזות האלה. תמיד עדיף להשתמש בפקודות מאקרו כשנדרשת אינטראקציה עם שאר ה-crate. ↩