ระบบบิลด์รองรับการสร้างการเชื่อมโยงของ bindgen ผ่านrust_bindgen
ประเภทข้อบังคับ Bindgen ให้บริการการเชื่อมโยง FFI ของ Rust กับไลบรารี C (มีการรองรับ C++ แบบจำกัด ซึ่งกำหนดให้ต้องตั้งค่าพร็อพเพอร์ตี้ cppstd
)
การใช้งาน rust_bindgen ขั้นพื้นฐาน
ต่อไปนี้เป็นตัวอย่างวิธีกำหนดโมดูลที่ใช้ bindgen และวิธีใช้โมดูลนั้นในเคจ หากต้องการใช้การเชื่อมโยงของ 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
กำหนดส่วนหัว external/rust/libbuzz/libbuzz_wrapper.h
ของ Wrapper ซึ่งรวมส่วนหัวที่เกี่ยวข้องทั้งหมดไว้ดังนี้
// 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"],
}
ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ Flag ของ bindgen ได้ที่ส่วนการปรับแต่งการเชื่อมโยงที่สร้างขึ้นในคู่มือ bindgen
หากคุณใช้ส่วนนี้เพื่อกําหนดโมดูล rust_bindgen
เป็นส่วนสําคัญก่อนใช้มาโคร include!()
ให้กลับไปที่ข้อกําหนดเบื้องต้นในหน้าเครื่องมือสร้างแหล่งที่มา หากไม่ ให้ไปยังส่วนถัดไป
ใช้การเชื่อมโยงเป็นแพ็กเกจ
สร้าง 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
เดียวกันหรือโมดูลที่อยู่ด้านล่างในลําดับชั้นไดเรกทอรีเท่านั้นที่จะเห็น ซึ่งมีประโยชน์ 2 อย่าง ดังนี้
- ไม่แนะนำให้ใช้การเชื่อมโยง C ดิบในส่วนอื่นๆ ของต้นไม้
- ซึ่งจะช่วยหลีกเลี่ยงปัญหาการลิงก์แบบเพชรด้วยการผสมผสานการลิงก์แบบคงที่และแบบไดนามิก
โดยปกติแล้ว คุณควรจัดเตรียมไลบรารี Wrapper ที่ปลอดภัยสำหรับโมดูลที่สร้างขึ้นซึ่งคุณเพิ่มไว้ในโครงสร้างไดเรกทอรีเดียวกับการเชื่อมโยงที่มีไว้สำหรับนักพัฒนาซอฟต์แวร์คนอื่นๆ หาก Use Case ของคุณใช้ไม่ได้กับวิธีนี้ คุณสามารถเพิ่มแพ็กเกจอื่นๆ ลงในระดับการเข้าถึงได้ เมื่อเพิ่มขอบเขตการมองเห็นเพิ่มเติม โปรดตรวจสอบว่าคุณไม่ได้เพิ่มขอบเขต 2 รายการที่อาจลิงก์กับกระบวนการเดียวกันในอนาคต เนื่องจากอาจลิงก์ไม่สำเร็จ
พร็อพเพอร์ตี้ rust_bindgen ที่โดดเด่น
พร็อพเพอร์ตี้ที่กําหนดไว้ด้านล่างนี้นอกเหนือจากพร็อพเพอร์ตี้ทั่วไปที่สําคัญซึ่งใช้กับข้อบังคับทั้งหมด รายการเหล่านี้มีความสำคัญอย่างยิ่งต่อโมดูล Rust ของ bndgen หรือแสดงลักษณะการทำงานที่ไม่ซ้ำกันเฉพาะสำหรับประเภทโมดูล rust_bindgen
stem, name, crate_name
rust_bindgen
จะสร้างตัวแปรของไลบรารี ดังนั้นจึงมีข้อกำหนดเดียวกันกับโมดูล rust_library
สำหรับพร็อพเพอร์ตี้ stem
, name
และ crate_name
ดูข้อมูลอ้างอิงจากพร็อพเพอร์ตี้คลัง Rust ที่โดดเด่น
wrapper_src
นี่คือเส้นทางแบบสัมพัทธ์ไปยังไฟล์ส่วนหัวของ Wrapper ที่มีส่วนหัวที่จําเป็นสําหรับการเชื่อมโยงเหล่านี้ นามสกุลไฟล์จะกำหนดวิธีตีความส่วนหัว และกำหนด Flag -std
ที่จะใช้โดยค่าเริ่มต้น ระบบจะถือว่านี่คือส่วนหัว Cเว้นแต่ส่วนขยายจะเป็น .hh
หรือ .hpp
หากส่วนหัว C++ ต้องมีนามสกุลอื่น ให้ตั้งค่าพร็อพเพอร์ตี้ cpp_std
เพื่อลบล้างลักษณะการทำงานเริ่มต้นที่ถือว่าไฟล์นั้นเป็นไฟล์ C
source_stem
นี่คือชื่อไฟล์ของไฟล์ต้นฉบับที่สร้างขึ้น ต้องกำหนดช่องนี้ แม้ว่าจะใช้การเชื่อมโยงเป็น Crate ก็ตาม เนื่องจากพร็อพเพอร์ตี้ stem
จะควบคุมเฉพาะชื่อไฟล์เอาต์พุตสำหรับตัวแปรของไลบรารีที่สร้างขึ้นเท่านั้น
หากโมดูลใช้เครื่องมือสร้างแหล่งที่มาหลายรายการ (เช่น bindgen
และ protobuf
) เป็นแหล่งที่มาแทนที่จะใช้กับ Crate ผ่าน rustlibs
คุณต้องตรวจสอบว่าเครื่องมือสร้างแหล่งที่มาทั้งหมดที่เป็น Dependency ของโมดูลนั้นมีค่า source_stem
ที่ไม่ซ้ำกัน โมดูลที่ขึ้นต่อกันจะคัดลอกแหล่งที่มาจาก 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
แสดงรายการสตริงของ Flag ของ Clang ที่จําเป็นต่อการตีความส่วนหัวอย่างถูกต้อง
custom_bindgen
สำหรับ Use Case ขั้นสูง คุณสามารถใช้ 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 สําหรับฟังก์ชันแบบคงที่ในบรรทัด ซึ่งสามารถรวมไว้ในการเชื่อมโยง 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: ["."],
}