מערכת ה-build תומכת ביצירת קישורים של bindgen באמצעות סוג המודול rust_bindgen
. Bindgen מספק קישורי FFI של Rust לספריות C (עם תמיכה מוגבלת ב-C++, שדורשת הגדרה של המאפיין cppstd
).
שימוש בסיסי ב-rust_bindgen
בהמשך מופיעה דוגמה להגדרת מודול שמשתמש ב-bindgen, וגם דוגמה לשימוש באותו מודול כ-crate. אם אתם צריכים להשתמש בקישורי מקשר דרך מאקרו include!()
, למשל לקוד חיצוני, עיינו בדף מחוללי מקור.
דוגמה לספריית C לקריאה מ-Rust
בהמשך מופיעה דוגמה לספריית C שמגדירה מבנה ופונקציה לשימוש ב-Rust.
external/rust/libbuzz/libbuzz.h
typedef struct foo {
int x;
} foo;
void fizz(int i, foo* cs);
external/rust/libbuzz/libbuzz.c
#include <stdio.h>
#include "libbuzz.h"
void fizz(int i, foo* my_foo){
printf("hello from c! i = %i, my_foo->x = %i\n", i, my_foo->x);
}
הגדרת מודול rust_bindgen
מגדירים כותרת wrapper, external/rust/libbuzz/libbuzz_wrapper.h
, שכוללת את כל הכותרות הרלוונטיות:
// Include headers that are required for generating bindings in a wrapper header.
#include "libbuzz.h"
מגדירים את הקובץ Android.bp
כ-external/rust/libbuzz/Android.bp
:
cc_library {
name: "libbuzz",
srcs: ["libbuzz.c"],
}
rust_bindgen {
name: "libbuzz_bindgen",
// Crate name that's used to generate the rust_library variants.
crate_name: "buzz_bindgen",
// Path to the wrapper source file.
wrapper_src: "libbuzz_wrapper.h",
// 'source_stem' controls the output filename.
// This is the filename that's used in an include! macro.
//
// In this case, we just use "bindings", which produces
// "bindings.rs".
source_stem: "bindings",
// Bindgen-specific flags and options to customize the bindings.
// See the bindgen manual for more information.
bindgen_flags: ["--verbose"],
// Clang flags to be used when generating the bindings.
cflags: ["-DSOME_FLAG"],
// Shared, static, and header libraries which export the necessary
// include directories must be specified.
//
// These libraries will also be included in the crate if static,
// or propagated to dependents if shared.
// static_libs: ["libbuzz"]
// header_libs: ["libbuzz"]
shared_libs: ["libbuzz"],
}
למידע נוסף על השימוש בדגלים של קישור, ראו את הקטע הידני לקטע התאמה אישית של קישורים שנוצרו.
אם השתמשתם בקטע הזה כדי להגדיר מודול rust_bindgen
כדרישה מוקדמת לשימוש במאקרו include!()
, עליכם לחזור לקטע דרישה מוקדמת בדף 'גנרטורים של מקורות נתונים'. אם לא, ממשיכים לקטע הבא.
שימוש בקישור כ-crate
יוצרים את external/rust/hello_bindgen/Android.bp
עם התוכן הבא:
rust_binary {
name: "hello_bindgen",
srcs: ["main.rs"],
// Add the rust_bindgen module as if it were a rust_library dependency.
rustlibs: ["libbuzz_bindgen"],
}
יוצרים את external/rust/hello_bindgen/src/main.rs
עם התוכן הבא:
//! Example crate for testing bindgen bindings
fn main() {
let mut x = buzz_bindgen::foo { x: 2 };
unsafe { buzz_bindgen::fizz(1, &mut x as *mut buzz_bindgen::foo) }
}
לבסוף, קוראים לפקודה m hello_bindgen
כדי ליצור את קובץ הבינארי.
בדיקת קישורי Bindgen
קישורי Bindgen מכילים בדרך כלל מספר בדיקות פריסה שנוצרו כדי למנוע אי-התאמות בפריסה של הזיכרון. AOSP ממליץ להגדיר מודול בדיקה לבדיקות האלה, ושהבדיקות ירוצו כחלק מחבילת הבדיקות הרגילה של הפרויקט.
אפשר ליצור בקלות מודול rust_test
לבדיקה ב-external/rust/hello_bindgen/Android.bp
כדי ליצור אותם בקלות:
rust_test {
name: "bindings_test",
srcs: [
":libbuzz_bindgen",
],
crate_name: "buzz_bindings_test",
test_suites: ["general-tests"],
auto_gen_config: true,
// Be sure to disable lints as the generated source
// is not guaranteed to be lint-free.
clippy_lints: "none",
lints: "none",
}
חשיפה וקישור
קישורים שנוצרים הם בדרך כלל קטנים מאוד, כי הם מורכבים מהגדרות של סוגים, חתימות של פונקציות וקבועים קשורים. לכן, בדרך כלל לא כדאי לקשר את הספריות האלה באופן דינמי. השבתנו את הקישור הדינמי של המודולים האלה, כך ששימוש בהם דרך rustlibs
יבחר באופן אוטומטי וריאנט סטטי.
כברירת מחדל, למודולים של rust_bindgen
יש מאפיין visibility
של [":__subpackages__"]
, שמאפשר רק למודולים באותו קובץ Android.bp
או במודולים שמתחתיו בהיררכיית הספריות לראות אותו. יש לכך שני מטרות:
- הוא מעודד להימנע משימוש בקישוריות C גולמיות במקומות אחרים בעץ.
- היא מונעת בעיות שקשורות לקישור משולש באמצעות שילוב של קישור סטטי ודינמי.
בדרך כלל, צריך לספק ספריית עטיפה בטוחה סביב המודול שנוצר שהוספתם לאותו עץ ספריות שבו הוספתם את הקישורים, והיא מיועדת לשימוש של מפתחים אחרים. אם הפתרון הזה לא מתאים לתרחיש לדוגמה שלכם, תוכלו להוסיף חבילות נוספות לקטע חשיפה. כשמוסיפים היקפי חשיפה נוספים, חשוב לא להוסיף שני היקפים שעשויים להיות מקושרים לאותו תהליך בעתיד, כי יכול להיות שהקישור לא יתבצע.
מאפיינים בולטים של rust_bindgen
המאפיינים שמפורטים בהמשך הם בנוסף למאפיינים משותפים חשובים שחלים על כל המודולים. הם חשובים במיוחד למודולים של Rust ב-bindgen, או שהם מציגים התנהגות ייחודית ספציפית לסוג המודול rust_bindgen
.
stem, name, crate_name
rust_bindgen
יוצר וריאנטים של ספריות, ולכן הם חולקים את אותן דרישות עם המודולים של rust_library
למאפיינים stem
, name
ו-crate_name
. למידע נוסף, ראו מאפיינים בולטים בספריות Rust.
wrapper_src
זהו הנתיב היחסי לקובץ כותרת של עטיפה שכולל את הכותרות הנדרשות לקישורים האלה. סיומת הקובץ קובעת איך לפרש את הכותרת, ומגדירה את הדגל -std
שבו יש להשתמש כברירת מחדל. מניחים זאת ככותרת C, אלא אם הסיומת היא .hh
או .hpp
. אם לכותרת של C++ צריכה להיות תוספת אחרת, מגדירים את המאפיין cpp_std
כדי לשנות את התנהגות ברירת המחדל שמניחה שהקובץ הוא קובץ C.
source_stem
זהו שם הקובץ של קובץ המקור שנוצר. חובה להגדיר את השדה הזה, גם אם משתמשים בקישור כ-crate, כי המאפיין stem
קובע רק את שם הקובץ של הפלט של הווריאנטים של הספרייה שנוצרו.
אם מודול תלוי בכמה גנרטורים של מקורות (כמו bindgen
ו-protobuf
) כמקור ולא כקונטיינרים דרך rustlibs
, צריך לוודא שלכל הגנרטורים של המקורות שהם יחסי תלות של המודול הזה יש ערכים ייחודיים של source_stem
. מודולים תלויים מעתיקים מקורות מכל יחסי התלות של SourceProvider
שמוגדרים ב-srcs
לספרייה משותפת OUT_DIR
, כך שהתנגשויות ב-source_stem
יובילו למחיקה של קובצי המקור שנוצרו בספרייה OUT_DIR
.
c_std
זוהי מחרוזת שמייצגת את גרסת סטנדרט C שבה צריך להשתמש. הערכים החוקיים מפורטים בהמשך:
- גרסה ספציפית, למשל
"gnu11"
. "experimental"
, שהוא ערך שמוגדר על ידי מערכת ה-build בקובץbuild/soong/cc/config/global.go
, עשוי להשתמש בגרסאות טיוטה כמו C++1z כשהן זמינות.- לא מוגדר או
""
, שמציין שצריך להשתמש בברירת המחדל של מערכת ה-build.
אם ההגדרה הזו מוגדרת, המערכת מתעלמת מסיומת הקובץ ומניחה שהכותרת היא כותרת C. אי אפשר להגדיר את ההגדרה הזו באותו זמן שבו מוגדרת ההגדרה cpp_std
.
cpp_std
cpp_std
היא מחרוזת שמייצגת את גרסת C הרגילה שבה צריך להשתמש. הערכים התקפים:
- גרסה ספציפית, כמו
"gnu++11"
"experimental"
, שהוא ערך שמוגדר על ידי מערכת ה-build בקובץbuild/soong/cc/config/global.go
, עשוי להשתמש בגרסאות טיוטה כמו C++1z כשהן זמינות.- לא מוגדר או
""
, שמציין שצריך להשתמש בברירת המחדל של מערכת ה-build.
אם ההגדרה הזו מוגדרת, המערכת מתעלמת מסיומת הקובץ ומניחה שהכותרת היא כותרת של C++. אי אפשר להגדיר את ההגדרה הזו באותו זמן שבו מוגדרת ההגדרה c_std
.
דגלים
cflags
מספק רשימת מחרוזות של דגלים של Clang שנדרשים כדי לפרש את הכותרות בצורה נכונה.
custom_bindgen
לתרחישים מתקדמים של שימוש, אפשר להשתמש ב-bindgen כספרייה, שמספקת ממשק API שאפשר לשנות כחלק מקובץ בינארי מותאם אישית של Rust. השדה custom_bindgen
מקבל את שם המודול של מודול rust_binary_host
, שמשתמש ב-API של bindgen במקום בקובץ הבינארי הרגיל של bindgen
.
קובץ הבינארי המותאם אישית הזה צריך לצפות לארגומנטים באופן דומה ל-bindgen
, למשל:
$ my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]
רוב התהליך הזה מטופל על ידי ספריית bindgen
עצמה. אפשר לראות דוגמה לשימוש כזה ב-external/rust/crters/libsqlite3-sys/android/build.rs.
בנוסף, אפשר להשתמש במלוא קבוצת מאפייני הספרייה כדי לשלוט ב-compilation של הספרייה, אבל בדרך כלל אין צורך להגדיר או לשנות אותם.
handle_static_inline ו-static_inline_library
שני המאפיינים האלה מיועדים לשימוש יחד, ומאפשרים ליצור חבילות עטיפה לפונקציות סטטיות מוטמעות שאפשר לכלול בקישור של bindgen שיוצאו.
כדי להשתמש בהם, מגדירים את handle_static_inline: true
ואת static_inline_library
לערך cc_library_static
התואם שמגדיר את המודול rust_bindgen
כקלט מקור.
דוגמה לשימוש:
rust_bindgen {
name: "libbindgen",
wrapper_src: "src/any.h",
crate_name: "bindgen",
stem: "libbindgen",
source_stem: "bindings",
// Produce bindings for static inline fucntions
handle_static_inline: true,
static_inline_library: "libbindgen_staticfns"
}
cc_library_static {
name: "libbindgen_staticfns",
// This is the rust_bindgen module defined above
srcs: [":libbindgen"],
// The include path to the header file in the generated c file is
// relative to build top.
include_dirs: ["."],
}