将rust编译成库
上一章讲述了如何从rust中调用c库,这一章我们讲如何把rust编译成库让别的语言通过cffi调用。
调用约定和mangle
正如上一章讲述的,为了能让rust的函数通过ffi被调用,需要加上extern "C"
对函数进行修饰。
但由于rust支持重载,所以函数名会被编译器进行混淆,就像c++一样。因此当你的函数被编译完毕后,函数名会带上一串表明函数签名的字符串。
比如:fn test() {}
会变成_ZN4test20hf06ae59e934e5641haaE
. 这样的函数名为ffi调用带来了困难,因此,rust提供了#[no_mangle]
属性为函数修饰。 对于带有#[no_mangle]
属性的函数,rust编译器不会为它进行函数名混淆。如:
在nm中观察到为
至此,test
函数将能够被正常的由cffi
调用。
指定crate
类型
crate
类型rustc
默认编译产生rust
自用的rlib
格式库,要让rustc
产生动态链接库或者静态链接库,需要显式指定。
方法1: 在文件中指定。
在文件头加上
#![crate_type = "foo"]
, 其中foo
的可选类型有bin
,lib
,rlib
,dylib
,staticlib
.分别对应可执行文件,默认(将由
rustc
自己决定),rlib
格式,动态链接库,静态链接库。方法2: 编译时给rustc 传
--crate-type
参数。参数内容同上。方法3: 使用cargo,指定
crate-type = ["foo"]
,foo
可选类型同1
小技巧: Any
Any
由于在跨越ffi
过程中,rust
类型信息会丢失,比如当用rust
提供一个OpaqueStruct
给别的语言时:
以上代码中完全不知道foo
是一个什么东西。安全也无从说起了,只能靠文档。 因此在ffi
调用时往往会丧失掉rust
类型系统带来的方便和安全。在这里提供一个小技巧:使用Box<Box<Any>>
来包装你的类型。
rust
的Any
类型为rust
带来了运行时反射的能力,使用Any
跨越ffi
边界将极大提高程序安全性。
这样一来,就非常不容易出错了。
Last updated