use*_*899 5 programming-languages lang rust
我是 Rust 新手,刚刚读完这本书。我试图了解 Rust 中的所有内容是否都必须以源代码的形式分发,就像 golang 一样。这可能不是准确的提问方式,但这是我想知道的:
在 C/C++ 时代,我可以将代码编译到某个库(xx.a 或 xx.so)中,并将其与头文件一起分发给可以链接其代码的人,只要我们使用大约相同的编译器/操作系统/平台。现在,Rust 的每个依赖项都以源代码的形式从 crates.io 中提取,并在本地构建和链接。但是,如果由于某种原因我不想发布源代码而只想发布目标平台的库,可以通过操作工具链来完成此操作吗?我相信由于 Rust 的一些固有设计,这是不可能做到的。例如,我可以在 Rust 库中编写这样的代码:
pub trait Summary {
// snip
}
fn returns_summarizable() -> impl Summary {
// snip
}
Run Code Online (Sandbox Code Playgroud)
如果依赖于库的代码调用returns_summarizable,则编译器必须能够确定返回值的大小,以便在堆栈上为结果变量分配空间。这意味着虽然代码只关心它返回一些实现该Summary特征的类型,但编译器实际上必须知道它返回的具体类型。如果没有库的源代码,就无法完成此操作,甚至无法使用头文件之类的等效文件,因为头文件(如果存在)应该只包含特征声明,而不包含函数可能返回的任何内部类型。
我对此感到好奇,不是因为我想在没有源的情况下分发包,而是因为我想到借用检查器和编译器从不查看调用它的函数或方法的主体,而只查看签名。当函数像上面那样返回时,情况似乎并非如此impl xxx,因为 Rust 必须查看实际返回的实现类型来确定返回类型大小,对吗?
这里的主要问题是 Rust ABI 还不稳定。因此,很难正确分发“Rust 二进制文件”,因为它们只能与您编译它们的完全相同的编译器一起使用。即使是较小的版本更改也可能会破坏它们。
目前安全的选择是通过设置 crates 类型来分发staticlib和/或cdylibCargo.toml
[lib]
crate-type = ["staticlib", "cdylib"]
Run Code Online (Sandbox Code Playgroud)
//会分别产生静态库文件和动态*.a库文件,参见链接的参考文章。*.so*.dylib*.dll
缺点是它使用 FFI 接口,因此会失去一些 Rust 的表达能力,并且只能使用 C 兼容类型,从而排除了泛型之类的东西。
如果您不介意破坏/重建每个 Rust 小版本,您可以使用 Rust dylib:
[lib]
crate-type = ["dylib"]
Run Code Online (Sandbox Code Playgroud)
这将在 Linux 上生成一个lib<your_crate_name>.so。然后,您可以告诉 Cargo 使用构建脚本或类似脚本链接该文件:
fn main() {
println!("cargo:rustc-link-lib=dy_lib");
println!("cargo:rustc-link-search=/home/jona/projects/dy-lib/target/release");
}
Run Code Online (Sandbox Code Playgroud)
您还必须在 extern 块中直接在使用它的地方或在存根库中提供函数签名:
extern "Rust" {
fn your_exported_function(Vec<i8>, String) -> Result<(), &'static str>;
}
Run Code Online (Sandbox Code Playgroud)
请注意,由于泛型是通过单态实现的,因此仍然不允许它们,但您至少可以使用 Rust 表达类型系统的其余部分,尽管块中的所有函数extern都是隐式的unsafe。
| 归档时间: |
|
| 查看次数: |
1276 次 |
| 最近记录: |