一、前言
rust中多了很多类型的库,比如前面章节中我们提到基本的bin与lib这两种crate类型库。
如果你在命令行执行下列语句:
rustc --help
那么你将能找到这样的内容:
--crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]
上面的rustc是rust中用来编译代码的工具,当我们运行cargo build命令的时候,该命令底层会使用rustc去构建源码、编译为可执行文件。
比如你只有一个main.rs文件,那么可以这样执行:rustc main.rs,将该文件编译为可执行文件。
然后我们可以看到,在rust中crate的类型是非常多的:
- bin:二进制可执行文件,必须要有main函数作为入口
- lib:它是一种代理名称,指代后续所有类型的库,但其默认指代的是rlib
- rlib:rust专用的静态中间库格式,其用于纯rust项目库互相调用,比如bin中调用lib的crate内部函数,也是我们用的最多的一个类型。
- dylib:动态库,会生成相应的特定于系统的动态库文件,比如linux上为
.so,MacOs上为.dylib,Windows上为.dll,但这类动态库只能被rust写的程序调用。 - cdylib:c语言规范的动态库,也会生成.so、.dylib、.dll等特定于系统的动态库文件,但其会符合C语言规范,可以被其它语言调用,比如C/C++。
- staticlib:将编译为静态库文件,比如linux与mac上的.a文件,又或者windows上的.lib文件。
- proc-macro:专用于导出过程宏的库
二、库生成
下一步,我们来使用一下上面这些列举出来的类型库。
bin类型就不用多说了,我们直接来到后面的lib类型,首先用下面这条命令生成一个lib:
cargo new testlib --lib
此时该项目将为默认的rlib类型库,比如当我们构建它时:

就会生成rlib文件,这种文件不需要我们理会,因为这是rust特定的库格式文件,我们一般只需要在其它项目中引入该项目源码进行使用,至于编译链接库的过程则全部交由编译器去处理。
然后下一步我们来看一下其它类型库的编译方式,其实很简单:
你只需要添加一个配置项即可完成编译。
其它类型也是类似的,将这里的crate-type的值改为对应类型即可,非常简单。
三、库使用
对于rlib与dylib这两种类型的crate,都无需我们操心,因为其使用方法都是基于源码形式使用的。
比如先我有另外一个hello-world的bin类型crate:

并直接用相对路径将该dylib类型的crate引入,此时该库中默认公开了一个add的函数,那么我们就可以直接使用:

此时编译下面的bin类型crate,就会发现,其编译后的目录中会多出dll库:

此后如果你想要运行exe文件,那么就必须将这个dll文件也带着,否则就会运行不起来。
但对于cdylib与staticlib库来说,就不能像上面那样使用了。
首先是cdylib,也就是生成之后得到的dll或者其它系统的动态库文件,也当然也包括一些c/c++语言编写生成的动态库文件。
如果你想要让你的cdylib与staticlib库函数能够正常被其它语言调用,就一定要像下面这样写导出函数:
#[no_mangle]
pub extern "C" fn add(left: u64, right: u64) -> u64 {
left + right
}其中extern "C"代表导出为C格式的函数,no_mangle代表告诉rust编译器,不要去更改、修饰函数名,防止后面找不到这个函数。
此时我们需要添加一个crate来加载使用动态库中的函数:
cargo add libloading
使用方式如下:
由于从外部加载是一个非常不安全的行为,因此需要用unsafe块将其包裹起来。
注意此时这个testlib.dll库文件,是直接复制过来放在当前项目的根目录下的。
然后调用其上的get方法,传入函数名,就可以去查找函数了。
同时你需要在其返回值上、著名该函数的类型,比如这里的类型写的是:
ffi-export#[no_mangle]pub extern "C" fn add(left: u64, right: u64) -> u64 { left + right}意思就是这是一个不安全的、C编译格式的、两个参数与一个返回值均为u64类型的函数。
但实测前面的定语即使不加也不会出错,也就是可以简写为:
ffi-export#[no_mangle]pub extern "C" fn add(left: u64, right: u64) -> u64 { left + right}加载完成后,其返回值就是其加载得到的函数,直接调用即可。
除了动态库外,还有静态库,其使用起来相对更简单一些:

也无需其它库,直接添加一个编译指令即可:
#[cfg(any())]
#[link(name = "testlib", kind = "static")]
unsafe extern "C" {
fn external_add(left: u64, right: u64) -> u64;
}
extern "C" fn add(left: u64, right: u64) -> u64 {
left + right
}
fn main() {
let result = add(2, 3);
println!("Rust 中定义的 C ABI 函数:{result}");
}ffi-static#[cfg(any())]#[link(name = "testlib", kind = "static")]unsafe extern "C" {注意这里静态库同样也是直接放在项目根目录下的。
然后声明要导入的函数,也就是函数类型,注意外层同样要用extern "C"进行包裹。
由于外部导入函数是不安全的行为,所以使用的时候必须要添加unsafe块,然后在其内使用即可。
四、总结
虽然rust中crate的类型很多,但实际上总的来看,只有两种类型,一是bin、二是lib。
其中lib为一个统称,其默认行为是rlib,也就是rust专用的库格式,但可以自行修改为其它类型的库格式。
rlib与dylib的使用方法是结合rust源码使用的,并不推荐给其它语言使用,两者之间的唯一区别就是dylib为动态库形式,而rlib为静态库形式。
请开通后继续阅读后续 70% 并运行完整示例~