跨越不可能的 FFI 边界,以及我逐渐陷入疯狂的过程

这是一篇关于实现不同语言之间互操作性的技术文章,主要内容如下:

  • 背景与挑战:主流语言的开发需要大型公司支持,Scala 和 Kotlin 通过基于现有生态系统(Java)实现互操作性。对于低级别、内存安全的语言(如 Vale、Austral、Ante),无缝构建现有生态系统困难,尤其在与 Rust 互操作时,存在诸多难题,如调用函数困难、处理 Rust 的泛型和内存安全保证等。
  • 具体实现步骤

    • 收集类型信息:通过运行临时 Rust 程序获取 std::vec::Vec 的大小、对齐和真实名称等信息,以生成 C 程序所需的 Rust 代码。
    • 收集函数信息:最初尝试使用 std::any::type_name 等方法获取函数信息失败,后得知使用 rustdoc 的 JSON 输出并结合 rustdoc_types 库更易获取,该过程虽慢但能收集到各种函数、结构体等信息。
    • 处理 Rust 函数重载:Rust 存在函数重载,如 OsString 的 from 方法有多个重载版本,工具需更具体地指定调用的重载版本,通过遍历 impl 块和匹配泛型参数来确定正确的函数。
    • 实现重载解析和泛型:利用收集到的信息,通过遍历 std::ffi::OsString 的 impl 块,匹配用户指定的泛型和函数,实现重载解析和确定函数参数,但过程复杂且存在未处理的边缘情况。
    • 寻求更好的解决方案:尝试使用 Alex Kladov 提供的 Rust 魔法代码来处理函数重载,但仍遇到问题,最终在并行探索中找到更简单的解决方案,如 literallyvoid 提出的一行代码解决方案。
  • 最终 approach:工具读取 C 文件的 #pragma rsuse 行,生成临时 Rust 程序获取类型和函数信息,调用 cargo run 收集输出,利用 cargo rustdoc 信息纠正类型名称,生成允许 C 调用 Rust 函数的库,下一步将整合到 Vale 实现原始目标。
  • 未解决问题:仍存在一些关于语言定义结构体与 Rust 创建相关容器、无借用检查语言调用时的内存安全保证以及特定语言特性的维护等问题,将在后续讨论。
  • 感谢与展望:感谢众多帮助实现这一目标的人,包括提供关键思路和技术支持的人员,展望未来语言间互操作性的发展,希望能让世界各国语言更方便地调用 Rust 代码。
阅读 13
0 条评论