高级主题

外部函数接口

在Rust中,通过外部函数接口 (foreign function interface) 可以直接调用C语言库:

  1. extern crate libc;
  2. use libc::size_t;
  3. #[link(name = "snappy")]
  4. extern {
  5. fn snappy_max_compressed_length(source_length: size_t) -> size_t;
  6. }
  7. fn main() {
  8. let x = unsafe { snappy_max_compressed_length(100) };
  9. println!("max compressed length of a 100 byte buffer: {}", x);
  10. }

其中#[link]属性用来指示链接器链接snappy库,extern块是外部库函数标记的列表。
外部函数被假定为不安全的,所以调用它们需要包装在unsafe块中。

当然,我们也可以把Rust代码编译为动态库来供其它语言调用:

  1. // in embed.rs
  2. use std::thread;
  3. #[no_mangle]
  4. pub extern "C" fn process() {
  5. let handles: Vec<_> = (0..10).map(|_| {
  6. thread::spawn(|| {
  7. let mut _x = 0;
  8. for _ in (0..5_000_001) {
  9. _x += 1
  10. }
  11. })
  12. }).collect();
  13. for h in handles {
  14. h.join().ok().expect("Could not join a thread!");
  15. }
  16. }

其中#[no_mangle]属性用来关闭Rust的命名改编,
默认的应用二进制接口 (application binary interface) "C"可以省略。
然后使用rustc进行编译:

  1. $ rustc embed.rs -O --crate-type=dylib

这将生成一个动态库libembed.so。在Node.js中调用该函数,需要安装ffi库:

  1. $ npm install ffi
  1. // in test.js
  2. var ffi = require('ffi');
  3. var lib = ffi.Library('libembed', {
  4. 'process': [ 'void', [] ]
  5. });
  6. lib.process();
  7. console.log("done!");

其中ffi.Library()用来加载动态库libembed.so
它需要标明外部函数的返回值类型和参数类型 (空数组表明没有参数)。