1 个不稳定版本
0.0.1 | 2024 年 6 月 14 日 |
---|
#6 in #libopus
1.5MB
48K SLoC
unsafe-libopus
本库是使用 c2rust 将 C 语言编写的 libopus 1.3.1 转译为 unsafe Rust 的。
它被称为 "unsafe" libopus,因为它在很大程度上保持了与 C 代码相同的结构,并且充满了 "unsafe"。
这种转译仍然允许您摆脱 C 编译器工具链,并在纯 Rust 环境中使用该库,无需链接器黑客攻击和动态链接问题。
它也可能是 libopus 更 Rust 风格实现的起点,尽管我不确定这是否值得努力。
使用方法
您可以通过使用来自 此 PR 的 opus
crate 的分支来利用这个库。
[dependencies]
opus = { git = "https://github.com/DCNick3/opus-rs.git", branch = "unsafe-libopus", default-features = false, features = ["unsafe-libopus-backend"] }
也许,这个库将来会有安全的 API,但现在,它是一个(主要是)可以直接替换 audiopus_sys
crate 的替代品。
转译技术
首先,使用以下命令编译了 libopus 1.3.1:
CC=clang ./configure --disable-shared --disable-stack-protector --enable-extra-programs --disable-doc --disable-asm --disable-rtcd --disable-intrinsics --disable-dependency-tracking--disable-maintainer-mode --enable-hardening
CC=clang compiledb make -j
然后,使用生成的 compile_commands.json
文件,使用以下方式将 C 代码转译为 Rust:
c2rust transpile compile_commands.json -o . --overwrite-existing --reorganize-definitions --emit-modules --translate-const-macros --emit-build-files
然后将生成的代码手动重新组织,以删除所有结构重复并消除对 #[no_mangle] extern "C"
函数的使用:它们现在都链接到 Rust,无需导出。
其他重构包括
- 将测试二进制文件与库分开,作为 "examples"
- 通过在库中定义它们的变体来删除库中对 libc 函数的依赖(来自 unsafe-libyaml 的想法)
- 通过用具体的Rust类型替换libc类型(例如
libc::c_int
->i32
等)来移除对libc crate的依赖。 - 通过用自定义的VarArgs结构体替换C的varargs,因为Rust中的C变长参数还不稳定。这使得
opus_*_ctl
系列函数变成了宏。
性能
这个库在翻译时没有使用内联汇编、处理器内嵌函数和运行时CPU检测,所以它现在的速度不如原始代码快。具有这些功能的C版本在我的机器上比Rust版本快约20%。
正确性与安全性
这个库使用(大部分)C代码库中的原始测试进行测试。它们以Rust集成测试的形式存在于 tests
目录中。
opus的测试向量也用于在CI中测试库的解码器(见 src/bin/run_vectors.rs
)。这几乎确保了解码器的正确性。这实际上帮助发现了 c2rust中的一个微妙错误。
编码器的正确性是一个更加开放的问题,因为据我所知,还没有针对它的测试向量。在 tests/opus_encode
中进行了一些测试,但相当有限。
至于安全性,没有任何保证。代码是C代码的直接转换结果,因此几乎全部是unsafe代码(在Rust术语中)。
它似乎也根据miri有UB,但这些可能是假阳性。一个好的重构目标可能是使库通过miri检查。
依赖项
~0.2–1.2MB
~23K SLoC