מערכת ה-build תומכת ביצירת קשרי bindgen באמצעות סוג המודול rust_bindgen
module. Bindgen מספקת קישורי Rust FFI לספריות C (עם תמיכה מוגבלת ב-C++, שדורשת הגדרה של המאפיין cppstd
).
שימוש בסיסי ב-rust_bindgen
בהמשך מופיעה דוגמה להגדרת מודול שמשתמש ב-bindgen, ואיך להשתמש במודול הזה כ-crate. אם אתם צריכים להשתמש בקישורי bindgen דרך מאקרו 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"],
}
מידע נוסף על שימוש בדגלי bindgen זמין בקטע Customizing Generated Bindings במדריך bindgen.
אם השתמשתם בקטע הזה כדי להגדיר מודול rust_bindgen
כתנאי מוקדם לשימוש בפקודת המאקרו include!()
, אתם צריכים לחזור אל תנאי מוקדם בדף Source Generators (מחוללי מקורות). אם לא, ממשיכים לקטעים הבאים.
שימוש ב-bindings כ-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 גולמיות במקומות אחרים בעץ.
- הוא מונע בעיות בקישור יהלומים באמצעות שילוב של קישור סטטי ודינמי.
בדרך כלל, כדאי לספק ספריית wrapper בטוחה סביב המודול שנוצר והוספתם באותו עץ ספריות כמו הקישורים, כדי שמפתחים אחרים יוכלו להשתמש בה. אם זה לא מתאים לתרחיש השימוש שלכם, אתם יכולים להוסיף חבילות נוספות לvisibility. כשמוסיפים היקפי חשיפה נוספים, חשוב לוודא שלא מוסיפים שני היקפי חשיפה שאולי יקושרו לאותו תהליך בעתיד, כי יכול להיות שהקישור ייכשל.
מאפיינים בולטים של rust_bindgen
המאפיינים שמוגדרים בהמשך הם בנוסף למאפיינים משותפים חשובים
שחלים על כל המודולים. הם חשובים במיוחד למודולים של Rust bindgen, או שהם מציגים התנהגות ייחודית שספציפית לסוג המודול rust_bindgen
.
stem, name, crate_name
rust_bindgen
יוצר וריאציות של ספריות, ולכן הן חולקות את אותן דרישות עם מודולי rust_library
של המאפיינים stem
, name
ו-crate_name
. לעיון, אפשר לעיין במאפיינים חשובים של ספריית Rust.
wrapper_src
זהו הנתיב היחסי לקובץ כותרת של wrapper שכולל את הכותרות הנדרשות לקישורים האלה. סיומת הקובץ קובעת איך לפרש את הכותרת ואיזה דגל -std
להגדיר כברירת מחדל. ההנחה היא שזהו כותר C
אלא אם התוסף הוא .hh
או .hpp
. אם לקובץ הכותרת של C++ צריך להיות סיומת אחרת, צריך להגדיר את המאפיין cpp_std
כדי לשנות את התנהגות ברירת המחדל, שמניחה שהקובץ הוא קובץ C.
source_stem
זה שם הקובץ של קובץ המקור שנוצר. חובה להגדיר את השדה הזה, גם אם משתמשים בקשירות כארגז, כי המאפיין stem
שולט רק בשם קובץ הפלט של הווריאציות של הספריות שנוצרו.
אם מודול מסוים תלוי בכמה גנרטורים של מקורות (כמו bindgen
ו-protobuf
) כמקור ולא כתיבות דרך rustlibs
, צריך לוודא שלכל הגנרטורים של המקורות שתלויים במודול הזה יש ערכי source_stem
ייחודיים. מודולים תלויים מעתיקים מקורות מכל יחסי התלות SourceProvider
שמוגדרים ב-srcs
לספרייה משותפת OUT_DIR
, כך שקונפליקטים ב-source_stem
יובילו להחלפה של קובצי המקור שנוצרו בספרייה OUT_DIR
.
c_std
זוהי מחרוזת שמייצגת את הגרסה של תקן C שבה רוצים להשתמש. הערכים האפשריים מפורטים בהמשך:
- גרסה ספציפית, כמו
"gnu11"
. -
"experimental"
, שהוא ערך שמוגדר על ידי מערכת הבנייה ב-build/soong/cc/config/global.go
, עשוי להשתמש בגרסאות טיוטה כמו C++1z כשהן זמינות. - לא מוגדר או
""
, שמציין שצריך להשתמש בברירת המחדל של מערכת ה-build.
אם ההגדרה הזו מוגדרת, המערכת מתעלמת מסיומת הקובץ ומניחה שהכותרת היא כותרת C. אי אפשר להגדיר את ההגדרה הזו בו-זמנית עם cpp_std
.
cpp_std
cpp_std
היא מחרוזת שמייצגת את גרסת תקן C שבה יש להשתמש. הערכים התקפים:
- גרסה ספציפית, כמו
"gnu++11"
-
"experimental"
, שהוא ערך שמוגדר על ידי מערכת הבנייה ב-build/soong/cc/config/global.go
, עשוי להשתמש בגרסאות טיוטה כמו C++1z כשהן זמינות. - לא מוגדר או
""
, שמציין שצריך להשתמש בברירת המחדל של מערכת ה-build.
אם ההגדרה הזו מוגדרת, המערכת מתעלמת מסיומת הקובץ ומניחה שהכותרת היא כותרת C++. אי אפשר להגדיר את ההגדרה הזו בו-זמנית עם c_std
.
cflags
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/crates/libsqlite3-sys/android/build.rs.
בנוסף, אפשר להשתמש בכל המאפיינים של הספרייה כדי לשלוט בהידור שלה, אבל בדרך כלל אין צורך להגדיר או לשנות אותם.
handle_static_inline ו-static_inline_library
שני הנכסים האלה מיועדים לשימוש משותף ומאפשרים יצירה של wrappers לפונקציות סטטיות מוטבעות שאפשר לכלול בהתקשרויות 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: ["."],
}