资讯详情

资讯详情

从 C++ 目标依赖 Rust 代码:comprehensive-rust 课程中 Chromium 构建规则的依赖实战

从 C 目标依赖 Rust 代码comprehensive-rust 课程中 Chromium 构建规则的依赖实战【免费下载链接】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 课程Google Android 团队使用的 Rust 教学仓库中 Chromium 模块的构建规则章节讲清Chromium 的 C 目标如何依赖 Rust 代码这一核心问题。读完你将掌握在 GN/Ninja 构建体系下声明rust_static_library、让 C 目标将其加入deps的完整做法并理解这种依赖关系成立的两个互操作前提纯 C API 或 C/Rust 互操作工具以及allow_unsafe、cxx_bindings等关键构建参数的含义。为什么 Chromium 中 Rust 与 C 的边界由 GN 构建规则表达Chromium 代码库不使用cargo构建 Rust 代码而是使用gn和ninja——其静态构建规则允许最大化并行编译Rust 代码也不例外。因此依赖 Rust 代码这件事在 Chromium 语境下首先是一个构建规则GN target 的deps问题其次才是语言互操作问题。课程在 build-rules 总览页 中给出了声明 Rust 目标的基线写法import(//build/rust/rust_static_library.gni) rust_static_library(my_rust_lib) { crate_root lib.rs sources [ lib.rs ] }这里有两个必须同时给出的字段理解它们是理解后续依赖关系的基础crate_root交给 Rust 编译器的编译单元根文件通常是lib.rssources完整的源文件清单ninja依赖它来判断何时需要触发重建。课程特别指出Rust 世界中没有source_set这一概念因为整个 crate 才是一个编译单元static_library就是最小的构建单元。此外课程还解释了为什么使用自定义的//build/rust/rust_static_library.gni模板而不是 GN 内置的 Rust 支持——该模板额外提供了 CXX 互操作、Rust 新特性以及单元测试的支持这些正是从 C 依赖 Rust整条链路能跑通的关键。核心操作把 Rust 目标加入 C 目标的depsdepending.md 给出的核心结论非常直接只需把上面的 Rust 目标加入某个 Chromium C 目标的deps即可。完整示例如下import(//build/rust/rust_static_library.gni) rust_static_library(my_rust_lib) { crate_root lib.rs sources [ lib.rs ] } # or source_set, static_library etc. component(preexisting_cpp) { deps [ :my_rust_lib ] }这段配置表达了完整的依赖拓扑rust_static_library(my_rust_lib)声明了一个 Rust 静态库目标component(preexisting_cpp)注释说明同样适用于source_set、static_library等 C 目标类型通过deps [ :my_rust_lib ]声明对它的依赖构建时 GN/Ninja 会先编译 Rust crate 并产出静态库再将其链接进 C 目标的最终产物。也就是说依赖在构建层是一次deps声明但课程在该页的展开注释中紧接着给出了一个关键限定下文两节专门展开这种依赖关系只有在满足互操作前提时才真正可用——要么 Rust 代码暴露可从 C 调用的纯 C API要么使用 C/Rust 互操作工具。前提一Rust 暴露纯 C API最低公分母方案当 Rust 侧只提供 C ABI 函数时C 侧通过extern C声明来消费它。仓库中的 构建规则练习 完整演示了这条链路可以作为依赖关系可用的最小实例在//ui/base/BUILD.gn中新增 Rust 目标crate 内容为# // Copyright 2023 Google LLC # // SPDX-License-Identifier: Apache-2.0 # // SAFETY: There is no other global function of this name. #[unsafe(no_mangle)] pub extern C fn hello_from_rust() { println!(Hello from Rust!) }然后把该 Rust 目标声明为//ui/base:base的依赖并在 C 侧练习建议放在ui/base/resource/resource_bundle.cc顶部声明并调用extern C void hello_from_rust();从 C 函数中调用它构建并运行 Chromium即可观察到 Hello from Rust! 被打印。这里有两个要点值得注意#[unsafe(no_mangle)]被 Rust 编译器视为一种不安全特性它允许生成同名函数编译器无法再保证调用到正确的那个因此 GN 目标中必须设置allow_unsafe true才能通过构建该方案退化到了两种语言都能原生声明和调用的 C ABI——C 和 Rust 都可以直接声明 C ABI 函数这也是它作为入门方案的价值链路短、易于排错。前提二使用 CXX 互操作工具直连 C 与 Rust手工extern C绑定在函数签名复杂时既繁琐又易错因此课程推荐 Chromium 实际采用的做法使用 CXX 工具在#[cxx::bridge]接口定义中描述整个语言边界由工具同时生成 Rust 和 C 两侧的声明。仓库内保留了 CXX 的第三方引用代码 third_party/cxx其 overview.svg 描述了整体机制同一份接口定义分别生成 C 与 Rust 侧代码两者最终通过一个最低公分母的 C API 通信。仓库中 blobstore 示例的 BUILD 文件 展示了这套生成物如何组织——rust_cxx_bridge从src/main.rs提取 bridge 定义生成绑定cc_library如:blobstore-sys依赖:bridge/include中生成的头文件Rust 侧二进制则依赖生成的桥接代码与//:cxx核心库。在 Chromium 中启用 CXX 的具体构建配置见 using-cxx-in-chromium.md为每个需要 Rust 的叶子节点定义一个独立的#[cxx::bridge] mod通常每个rust_static_library一个并在目标中追加cxx_bindings [ my_rust_file.rs ] # list of files containing #[cxx::bridge], not all source files allow_unsafe true随后 C 侧直接包含生成的头文件即可#include ui/base/my_rust_file.rs.h注意cxx_bindings列出的是包含 bridge 的文件而非全部源文件。此外//base下提供了一批在 Chromium C 类型与 CXX Rust 类型之间转换的实用函数例如SpanToRustSlice用于跨越 FFI 边界时的类型适配。为什么 CXX 路径下仍然需要allow_unsafe true课程对此给出了宽泛与精确两层解释宽泛层面按 Rust 的标准没有任何 C/C 代码是安全的——从 Rust 来回调用 C/C 可能任意操纵内存破坏 Rust 自身数据布局的安全假设。把任何外部代码引入 Rust 二进制都可能从 Rust 视角产生不可预期的行为精确层面CXX 在幕后生成的正是我们手工方案里写过的 Rustunsafe与extern C函数——接口定义语言的自动化不会消除底层的 unsafe 本质只是消除了两侧声明不同步导致的未定义行为手工绑定不同步是 UBCXX 绑定不同步则是编译错误。CXX 相对手工绑定的收益在 interoperability-with-cpp 总览页 中被系统归纳保证两侧声明一致#[cxx::bridge]与实际 C/Rust 定义不匹配时直接报编译错误而手工绑定失步会得到未定义行为自动生成 FFI thunk为方法调用等非 C 特性生成 C-ABI 兼容的自由函数无需手工编写内建核心类型支持[T]可跨 FFI 边界传递各语言对空 slice 的表示略有差异手工拆解重建指针/长度极易出错std::unique_ptrT、std::shared_ptrT与Box原生支持手工绑定只能传裸指针抬高生命周期与内存安全风险rust::String/CxxString处理两种语言字符串表示的差异如lossy从非 UTF-8 输入构造字符串、c_str做 NUL 终止。依赖方向的另一半Rust 目标依赖其他 Rust 目标从 C 依赖 Rust之外rust_static_library的deps同样可以指向其他 Rust 目标——build-rules 总览页 明确预告了这一能力会用于依赖第三方 crate。当依赖的是已通过构建规则生成目标的第三方 crate 时做法是找到你的rust_static_library目标添加对 crate 内:lib目标的dep路径形式为//third_party/rust/crate 名/vmajor 版本号:librust_static_library(my_rust_lib) { crate_root lib.rs sources [ lib.rs ] deps [ //third_party/rust/example_rust_crate/v1:lib ] }这一规则细节见 depending-on-a-crate.md与本页的 C→Rust 依赖构成完整的依赖拓扑。小结与可验证依据要点做法依据C 目标依赖 Rust 目标C 目标component/source_set/static_library等的deps中加入:my_rust_libdepending.md声明 Rust 目标rust_static_library必须同时给出crate_root与完整sourcesRust 无source_setcrate 即编译单元build-rules.md依赖成立的互操作前提纯 C APIextern Cno_mangle或 CXX 互操作工具depending.md、using-cxx-in-chromium.mdallow_unsafe true的必要性no_mangle与 CXX 生成的unsafe/extern C代码均属 unsafe需显式放行构建规则练习、using-cxx-in-chromium.mdCXX 机制接口定义语言统一生成双侧声明底层经 C ABI 通信绑定失步即编译错误interoperability-with-cpp.md、blobstore BUILDRust 依赖第三方 cratedeps [ //third_party/rust/crate/vmajor:lib ]depending-on-a-crate.md需要注意的适用前提以上内容对应的是 Chromium 构建体系GN Ninja //build/rust/rust_static_library.gni模板文中涉及的//ui/base/BUILD.gn、//base等路径属于 Chromium 源码树而非本仓库本仓库内可直接查证的是课程文档与third_party/cxx下的 CXX 引用示例代码。【免费下载链接】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),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →