
Android 构建集成在 Soong 中用 rust_binary 构建 CXX Rust 桥接模块【免费下载链接】comprehensive-rustThis is the Rust course used by the Android team at Google. It provides you the material to quickly teach Rust.项目地址: https://gitcode.com/GitHub_Trending/co/comprehensive-rust本篇技术指南基于 comprehensive-rust 课程中《Building in Android》章节讲解在 Android 的 Soong 构建系统中如何把 CXX 生成的 Rust↔C 桥接代码编译为可运行的rust_binary。你将掌握rust_binary模块中rustlibs与static_libs的职责分工、配合genrule生成 C 桥接头文件/源文件的标准流程并得到一个可直接参考的完整Android.bp实例为在 Android 平台上安全地双向调用 Rust 与 C 代码打下构建层面的基础。CXX 与 Android 构建的整体关系With C 章节指出Android 平台上 Rust 与 C 的互操作依靠 CXX crate课程在 third_party/cxx 目录中内置了该 crate 的副本与示例。CXX 的核心机制是桥接模块bridge module在 Rust 源码中通过#[cxx::bridge]属性宏声明一个ffi模块描述两个语言互相暴露的函数签名与类型然后由 CXX 的代码生成器分别产出 Rust 侧与 C 侧的胶水代码实现类型安全、内存安全的双向调用。在 Android 的构建体系Soong基于 Blueprint/Android.bp文件中这套流程需要三个层面的配合Rust 侧桥接声明由#[cxx::bridge]模块给出详见 The Bridge ModuleC 侧胶水代码生成由genrule调用cxxbridge工具生成详见 android-cpp-genrules.md最终可执行目标由rust_binary把 Rust 代码、CXX 运行库libcxx与编译好的 C 静态库链接到一起——这正是本文的核心文档 android-build-rust.md 所演示的内容。核心模块一个最小可用的 rust_binary 定义原文档给出的最小构建单元如下JavaScript 语法即 Soong 模块定义语言rust_binary { name: cxx_test, srcs: [lib.rs], rustlibs: [libcxx], static_libs: [libcxx_test_cpp], }逐字段拆解其含义与作用name: cxx_test模块名最终生成的二进制产物名即cxx_test也是其他模块依赖它的标识srcs: [lib.rs]Rust 源文件其中必须包含用#[cxx::bridge]标注的桥接模块通常放在ffi子模块中参见 The Bridge Modulerustlibs: [libcxx]链接 CXX 的 Rust 侧运行库。libcxx是 Android 平台预置的 CXX crate即cxx库它为桥接代码提供运行时支持内存布局、类型转换、异常处理等。没有它#[cxx::bridge]展开出的 Rust 代码将无法编译static_libs: [libcxx_test_cpp]链接一个cc_library_static类型的 C 静态库。该库包含桥接所需的 C 侧实现例如BlobstoreClient的 C 类实现以及由cxxbridge生成的桥接源码。一句话概括构建链路Rust 代码lib.rs CXX 运行库libcxx 已生成的 C 桥接代码与业务实现cc_library_static→ 链接成单一可执行文件。前置步骤用 genrule 生成 C 桥接胶水rust_binary依赖的cc_library_static并非空手而来。CXX 需要为 C 侧也生成一份匹配桥接声明的头文件和源文件这一步由 android-cpp-genrules.md 中的两个genrule完成// Generate a C header containing the C bindings // to the Rust exported functions in lib.rs. genrule { name: libcxx_test_bridge_header, tools: [cxxbridge], cmd: $(location cxxbridge) $(in) --header $(out), srcs: [lib.rs], out: [lib.rs.h], } // Generate the C code that Rust calls into. genrule { name: libcxx_test_bridge_code, tools: [cxxbridge], cmd: $(location cxxbridge) $(in) $(out), srcs: [lib.rs], out: [lib.rs.cc], }要点说明cxxbridge是 CXX 提供的独立命令行工具在 Android 平台被内置为 Soong tool可直接通过tools: [cxxbridge]引用第一个genrule追加--header参数产出 C 头文件声明 C 侧接口供 C 业务代码 include第二个genrule不带该参数产出 C 源文件实现 Rust 调进来的桩代码命名约定若 Rust 源文件为lib.rs则头文件为lib.rs.h、源文件为lib.rs.cc。这一约定并非强制但 Android 构建体系中的后续环节会按此约定消费产物这两个产物通过cc_library_static的generated_headers与generated_sources属性注入见下文的完整实例。完整实例仓库内置的 blobstore 项目课程仓库在 third_party/cxx/blobstore/Android.bp 中提供了一个可直接对照的完整示例把上述两节内容串成一条完整的构建链cc_library_static { name: blobstore_cpp, srcs: [src/blobstore.cc], generated_headers: [ cxx-bridge-header, blobstore_bridge_header ], generated_sources: [blobstore_bridge_code], } genrule { name: blobstore_bridge_header, tools: [cxxbridge], cmd: $(location cxxbridge) $(in) --header $(out), srcs: [src/main.rs], out: [main.rs.h], } genrule { name: blobstore_bridge_code, tools: [cxxbridge], cmd: $(location cxxbridge) $(in) $(out), srcs: [src/main.rs], out: [main.rs.cc], } rust_binary { name: blobstore, srcs: [src/main.rs], rustlibs: [libcxx], static_libs: [blobstore_cpp], }可以看到它与课程文档中的最小示例完全同构只是多了一层真实的业务实现genrule输入的是src/main.rs因为该示例的桥接模块声明在 third_party/cxx/blobstore/src/main.rs 中。产物按命名约定为main.rs.h与main.rs.cccc_library_staticblobstore_cpp的srcs是 src/blobstore.ccC 业务实现如BlobstoreClient类并通过generated_headers/generated_sources把两个genrule的产物编入自身。注意generated_headers中额外包含的cxx-bridge-header是 CXX 所需的公共头而blobstore_bridge_header才是本项目桥接生成的头rust_binaryblobstore通过rustlibs: [libcxx]获得 CXX Rust 运行库、通过static_libs: [blobstore_cpp]获得 C 静态库含生成代码与业务实现三者在链接期合并为最终可执行文件。桥接声明的样子third_party/cxx/blobstore/src/main.rs 中的桥接模块演示了三种典型的桥接内容读者可参照其结构编写自己的lib.rs#[allow(unsafe_op_in_unsafe_fn)] #[cxx::bridge(namespace org::blobstore)] mod ffi { // 共享结构体两个语言都可见的字段 struct BlobMetadata { size: usize, tags: VecString, } // Rust 侧暴露给 C 的类型与签名 extern Rust { type MultiBuf; fn next_chunk(buf: mut MultiBuf) - [u8]; } // C 侧暴露给 Rust 的类型与签名 unsafe extern C { include!(include/blobstore.h); type BlobstoreClient; fn new_blobstore_client() - UniquePtrBlobstoreClient; fn put(self: Pinmut BlobstoreClient, parts: mut MultiBuf) - u64; fn tag(self: Pinmut BlobstoreClient, blobid: u64, tag: str); fn metadata(self, blobid: u64) - BlobMetadata; } }对照 Rust Bridge Declarations 与 Generated C 章节可以理解extern Rust段声明引用父模块作用域内的 Rust 类型/函数CXX 据此生成对应的 C 头文件声明生成头与 Rust 源文件同路径、扩展名为.rs.hunsafe extern C段则通过include!引入 C 头并把BlobstoreClient等 C 类型以UniquePtr、Pinmut等方式安全地暴露给 Rust 侧调用。构建时的类型映射要点在编写桥接签名时应遵循 Additional Types 章节给出的映射表避免使用无法直接跨语言传递的类型Rust 类型C 类型Stringrust::Stringstrrust::StrCxxStringstd::string[T]/mut [T]rust::SliceBoxTrust::BoxTUniquePtrTstd::unique_ptrTVecTrust::VecTCxxVectorTstd::vectorT这些类型可用于共享结构体字段以及extern函数的参数与返回值。特别需要注意Rust 的String并不直接对应std::string——原因在于std::string不保证 UTF-8 不变式、两者内存布局不同无法直接跨语言传递且std::string的移动构造语义与 Rust 的 move 语义不匹配不能按值传给 Rust。调试与注意事项结合 The Bridge Module 的说明构建或运行桥接代码时还应留意查看生成的 Rust 代码常规 Cargo 工程可用cargo expand如cargo expand ::ffi只展开ffi模块查看宏展开后的桥接代码但该方式不适用于 Android 工程——Android 工程应直接查看构建产物查看生成的 C 代码在 Cargo 工程中可检查target/cxxbridge目录在 Android 工程中则对应genrule产出的*.rs.h/*.rs.cc文件rust_binary仅适用于产出可执行文件。若你的需求是把桥接代码编入共享库供其他模块加载则应将上述思路迁移到rust_library或rust_ffi等模块形态rustlibs与static_libs的搭配逻辑保持一致桥接模块中的unsafe extern C段是 CXX 安全模型的一部分跨语言边界的调用由 CXX 生成的胶水代码承担不安全的底层细节业务代码无需手写unsafe块来操作裸指针。总结在 Android 上构建 CXX 桥接代码的标准流程可以归纳为三步在 Rust 源文件中用#[cxx::bridge]声明桥接模块示例见 src/main.rs用两个genrulecxxbridge工具生成 C 侧头文件与源文件并作为generated_headers/generated_sources注入cc_library_static示例见 Android.bp用rust_binary聚合 Rust 源文件、rustlibs: [libcxx]与static_libs: [你的 cc_library_static]得到最终可执行文件。把最小示例与仓库内置的 blobstore 工程Android.bp、src/main.rs对照研读即可在 Android 平台上搭建出结构正确、可编译、可运行的 Rust↔C 互操作构建配置。【免费下载链接】comprehensive-rustThis is the Rust course used by the Android team at Google. It provides you the material to quickly teach Rust.项目地址: https://gitcode.com/GitHub_Trending/co/comprehensive-rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考