ระบบบิลด์รองรับการสร้าง Binding ของ Bindgen ผ่านประเภทโมดูล rust_bindgen Bindgen มี Binding ของ Rust FFI สำหรับไลบรารี C (โดยมีการรองรับ C++ แบบจำกัด ซึ่งต้องตั้งค่าพร็อพเพอร์ตี้ cppstd)
การใช้งาน rust_bindgen เบื้องต้น
ต่อไปนี้เป็นตัวอย่างวิธีกำหนดโมดูลที่ใช้ Bindgen และวิธีใช้โมดูลดังกล่าวเป็น Crate หากต้องการใช้ Binding ของ Bindgen ผ่าน
มาโคร include!() เช่น สำหรับโค้ดภายนอก โปรดดูหน้า
เครื่องมือสร้างแหล่งที่มา
ตัวอย่างไลบรารี C ที่จะเรียกจาก Rust
ต่อไปนี้เป็นตัวอย่างไลบรารี C ที่กำหนด Struct และฟังก์ชันสำหรับใช้ใน 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 ได้ในส่วนคู่มือ Bindgen เกี่ยวกับ การปรับแต่ง Binding ที่สร้างขึ้น
หากใช้ส่วนนี้เพื่อกำหนดโมดูล rust_bindgen เป็นข้อกำหนดเบื้องต้นสำหรับการใช้มาโคร include!() ให้กลับไปที่ ข้อกำหนดเบื้องต้นในหน้าเครื่องมือสร้างแหล่งที่มา หากไม่เป็นเช่นนั้น ให้ดำเนินการในส่วนถัดไป
ใช้ Binding เป็น 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 เพื่อสร้างไบนารี
ทดสอบ Binding ของ Bindgen
โดยปกติแล้ว Binding ของ 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",
}
ระดับการเข้าถึงและการลิงก์
โดยปกติแล้ว Binding ที่สร้างขึ้นจะมีขนาดเล็กมาก เนื่องจากประกอบด้วยการกำหนดประเภท ลายเซ็นฟังก์ชัน และค่าคงที่ที่เกี่ยวข้อง ดังนั้น การลิงก์ไลบรารีเหล่านี้แบบไดนามิกจึงเป็นการสิ้นเปลืองโดยทั่วไป เราได้ปิดใช้การลิงก์แบบไดนามิกสำหรับโมดูลเหล่านี้ เพื่อให้การใช้โมดูลผ่าน rustlibs จะเลือกตัวแปรแบบคงที่โดยอัตโนมัติ
โดยค่าเริ่มต้น โมดูล rust_bindgen มีพร็อพเพอร์ตี้ visibility เป็น
[":__subpackages__"] ซึ่งจะอนุญาตให้เฉพาะโมดูลในไฟล์ Android.bp
เดียวกันหรือโมดูลที่อยู่ใต้ไฟล์นั้นในลำดับชั้นของไดเรกทอรีเท่านั้นที่จะมองเห็นโมดูลดังกล่าว ซึ่งมีวัตถุประสงค์ 2 ประการดังนี้
- เพื่อไม่ให้มีการใช้ Binding C ดิบในที่อื่นๆ ในโครงสร้าง
- เพื่อหลีกเลี่ยงปัญหาการลิงก์แบบ Diamond ที่เกิดจากการลิงก์แบบคงที่และแบบไดนามิกผสมกัน
โดยปกติแล้ว คุณควรระบุไลบรารี Wrapper ที่ปลอดภัยรอบๆ โมดูลที่สร้างขึ้นซึ่งคุณเพิ่มในโครงสร้างไดเรกทอรีเดียวกันกับ Binding ที่มีไว้สำหรับนักพัฒนาซอฟต์แวร์คนอื่นๆ หากวิธีนี้ใช้ไม่ได้กับกรณีการใช้งานของคุณ คุณสามารถเพิ่ม แพ็กเกจเพิ่มเติมลงใน ระดับการเข้าถึงได้ เมื่อเพิ่มขอบเขตระดับการเข้าถึงเพิ่มเติม โปรดระมัดระวังไม่ให้เพิ่มขอบเขต 2 ขอบเขตที่อาจลิงก์เข้ากับกระบวนการเดียวกันในอนาคต เนื่องจากอาจทำให้ลิงก์ไม่สำเร็จ
พร็อพเพอร์ตี้ rust_bindgen ที่สำคัญ
พร็อพเพอร์ตี้ที่กำหนดไว้ด้านล่างนี้เป็นพร็อพเพอร์ตี้เพิ่มเติมจากพร็อพเพอร์ตี้ทั่วไปที่สำคัญ
ซึ่งใช้กับโมดูลทั้งหมด พร็อพเพอร์ตี้เหล่านี้มีความสำคัญอย่างยิ่งต่อโมดูล Rust Bindgen หรือแสดงลักษณะการทำงานที่ไม่ซ้ำกันซึ่งเฉพาะเจาะจงกับประเภทโมดูล rust_bindgen
stem, name, crate_name
rust_bindgen สร้างตัวแปรไลบรารี ดังนั้นจึงมีข้อกำหนดเดียวกันกับ
โมดูล rust_library สำหรับพร็อพเพอร์ตี้ stem, name และ crate_name ดูข้อมูลอ้างอิงได้ที่
พร็อพเพอร์ตี้ไลบรารี Rust ที่สำคัญ
wrapper_src
นี่คือเส้นทางแบบสัมพัทธ์ไปยังไฟล์ส่วนหัวของ Wrapper ซึ่งรวมส่วนหัวที่จำเป็นสำหรับ Binding เหล่านี้ นามสกุลไฟล์จะเป็นตัวกำหนดวิธีตีความส่วนหัวและกำหนดแฟล็ก -std ที่จะใช้โดยค่าเริ่มต้น ระบบจะถือว่าเป็นส่วนหัว C เว้นแต่ นามสกุลจะเป็น .hh หรือ .hpp หากส่วนหัว C++ ต้องมีนามสกุลอื่น ให้ตั้งค่าพร็อพเพอร์ตี้ cpp_std เพื่อลบล้างลักษณะการทำงานเริ่มต้นที่ถือว่าไฟล์เป็นไฟล์ C
source_stem
นี่คือชื่อไฟล์สำหรับ ไฟล์แหล่งที่มาที่สร้างขึ้น คุณ ต้อง กำหนดฟิลด์นี้ แม้ว่าคุณจะใช้ Binding เป็น Crate ก็ตาม เนื่องจากพร็อพเพอร์ตี้ stem จะควบคุมเฉพาะชื่อไฟล์เอาต์พุตสำหรับตัวแปรไลบรารีที่สร้างขึ้น
หากโมดูลขึ้นอยู่กับเครื่องมือสร้างแหล่งที่มาหลายรายการ (เช่น bindgen และ protobuf) เป็นแหล่งที่มาแทนที่จะเป็น Crate ผ่าน rustlibs คุณต้องตรวจสอบว่าเครื่องมือสร้างแหล่งที่มาทั้งหมดที่เป็นการขึ้นต่อกันของโมดูลนั้นมีค่า source_stem ที่ไม่ซ้ำกัน โมดูลที่ขึ้นต่อกันจะคัดลอกแหล่งที่มาจากทรัพยากร Dependency ทั้งหมดของ SourceProvider ที่กำหนดไว้ใน srcs ไปยังไดเรกทอรี OUT_DIR ทั่วไป ดังนั้นการชนกันใน source_stem จะทำให้ไฟล์แหล่งที่มาที่สร้างขึ้นถูกเขียนทับในไดเรกทอรี OUT_DIR
c_std
นี่คือสตริงที่แสดงเวอร์ชันมาตรฐาน C ที่จะใช้ ค่าที่ถูกต้องมีดังนี้
- เวอร์ชันที่เฉพาะเจาะจง เช่น
"gnu11" "experimental"ซึ่งเป็นค่าที่กำหนดโดยระบบบิลด์ในbuild/soong/cc/config/global.goอาจใช้ เวอร์ชันร่าง เช่น C++1z เมื่อพร้อมใช้งาน- ไม่ได้ตั้งค่าหรือ
""ซึ่งบ่งบอกว่าควรใช้ค่าเริ่มต้นของระบบบิลด์
หากตั้งค่านี้ ระบบจะเพิกเฉยต่อนามสกุลไฟล์และถือว่าส่วนหัวเป็นส่วนหัว C คุณตั้งค่านี้พร้อมกับ cpp_std ไม่ได้
cpp_std
cpp_std คือสตริงที่แสดงเวอร์ชันมาตรฐาน C ที่จะใช้ ค่าที่ถูกต้องมีดังนี้
- เวอร์ชันที่เฉพาะเจาะจง เช่น
"gnu++11" "experimental"ซึ่งเป็นค่าที่กำหนดโดยระบบบิลด์ในbuild/soong/cc/config/global.goอาจใช้ เวอร์ชันร่าง เช่น C++1z เมื่อพร้อมใช้งาน- ไม่ได้ตั้งค่าหรือ
""ซึ่งบ่งบอกว่าควรใช้ค่าเริ่มต้นของระบบบิลด์
หากตั้งค่านี้ ระบบจะเพิกเฉยต่อนามสกุลไฟล์และถือว่าส่วนหัวเป็นส่วนหัว 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
พร็อพเพอร์ตี้ทั้ง 2 รายการนี้มีไว้ให้ใช้ร่วมกันและอนุญาตให้สร้าง Wrapper สำหรับฟังก์ชันแบบคงที่แบบอินไลน์ ซึ่งสามารถรวมไว้ใน Binding ของ 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: ["."],
}
cc_library_static