C++ 与 Python 节点¶
已有的 C++ 或 Python 算法可以作为节点接进 System。工程仍然是一个 Rust 项目:Rust 声明消息和节点接口,构建脚本生成胶合代码和可编辑的外语文件,C++ / Python 只实现节点的算法;Rhythm 和 System 的组织留在 Rust。
本页的验证范围
本站的完整程序只覆盖纯 Rust。下面的外语流程来自 roplat 0.5 的构建工具,本站尚未用 crates.io 上的 roplat_build、roplat_cpp、roplat_py 包独立复现,签名以 docs.rs 为准。
流程¶
flowchart LR
A[Rust:#roplat_msg 消息<br>#roplat::node 外语节点声明] --> B[build.rs:提取元数据]
B --> C[生成胶合代码与基类]
B --> D[缺失时生成用户实现文件]
D --> E[你在 C++ / Python 里写 process]
C --> F[编译原生桥接]
E --> F
F --> G[System 里像普通节点一样连线]
- 声明消息。 跨语言传递的数据用
#[roplat::roplat_msg]标注#[repr(C)]结构体,构建时生成 C 头文件和 Python 类型。 - 声明节点。 在 Rust 里用
#[roplat::node(lang = "cpp", input(…), output(…))](Python 为lang = "py")声明一个外语节点的端口和配置字段。这个 Rust 结构体是接口声明,不是算法本身。 - 构建脚本。
build.rs使用roplat_build::BuildOrchestrator:先通过一次检查触发过程宏写出元数据,再生成文件,最后编译 C++ 桥接(cc或cmake后端)。 - 实现算法。 在生成的用户文件里实现
process。 - 连线。 在 System 里照常写
source >> forward >> sink;。
依赖¶
[dependencies]
roplat = "0.5.0"
roplat_py = "0.5.0" # 有 Python 节点时
tokio = { version = "1", features = ["macros", "rt-multi-thread", "sync", "time"] }
[build-dependencies]
roplat_build = "0.5.0"
C++ 节点的胶合由 roplat_build 生成并编译,需要本机有 C++ 工具链(使用 cmake 后端时还需要 CMake)。crates.io 上还有 roplat_cpp、roplat_cpp_msg 等 C++ 相关的包,用途以它们在 docs.rs 上的说明为准。
声明一个 C++ 节点¶
#[roplat::roplat_msg]
#[repr(C)]
#[derive(Clone, Debug, PartialEq)]
pub struct Packet {
pub id: u64,
pub value: f64,
}
#[roplat::node(
lang = "cpp",
input(input, Packet),
output(output, Packet)
)]
pub struct CppForward {
pub scale: f64,
}
// build.rs
use roplat_build::{BuildOrchestrator, NativeBackend, NativeBuildConfig};
fn main() {
// 提取阶段由过程宏完成,构建脚本直接返回。
if std::env::var("ROPLAT_PHASE").as_deref() == Ok("EXTRACT") {
return;
}
let native = NativeBuildConfig::new()
.backend(NativeBackend::Cc)
.library_name("my_nodes_cpp")
.include_dir("cpp/src");
BuildOrchestrator::new()
.native_build(native)
.build()
.expect("code generation failed");
println!("cargo:rerun-if-changed=src/");
println!("cargo:rerun-if-changed=cpp/src/");
}
构建后,cpp/roplat_gen/ 下是生成器管理的基类、消息头文件和 FFI 胶合,每次构建都会重写;cpp/src/ 下是你的实现文件,只在缺失时生成一次:
class CppForward : public CppForwardBase, public roplat::Node<Packet, Packet>
{
public:
Packet process(const Packet &input) override
{
Packet out;
out.id = input.id;
out.value = input.value * 2.0;
return out;
}
};
不要把算法写进 roplat_gen/ 下的文件,下次构建会覆盖它们。
Python 节点¶
声明时写 lang = "py",生成的 Python 用户文件形如:
class PyForward(PyForwardBase, Node):
def process(self, input_data: Packet) -> Packet:
out = Packet()
out.id = int(input_data.id)
out.value = float(input_data.value) + self.bias
return out
Python 节点需要匹配的 Python 开发环境。共享帧的只读视图需要可选的 buffer 扩展;扩展模块和嵌入解释器两种用法要分开构建,不要对整个工作区一次打开所有特性。
已知边界¶
- Rust 声明里的配置字段目前不会自动同步到外语实现;增加参数前先确认生成的接口提供了对应通路。
- 透明 Python 节点在启用时验证并缓存消息布局,返回时检查类型和长度,但不检查
bool等受限字段的位模式。节点放在周期内部时,每个周期都会重新支付这份初始化成本。 - 桥接里的失败目前走 panic,不属于合作式的失败与对象归还保证。
- Python 不透明节点的旧交接方式不支持任意多个在途调用、同类型分支并发和线程迁移。
- 跨语言传递不等于端到端零复制:Python 读取小消息得到的是副本。
需要逐条处理或跨进程的数据交换,见通信。