TL;DR

C使用dlopen系统调用,Rust用libloading这个板条箱。dlopen的用法可以看手册(RTFM)

man dlopen

Example of Rust

示例:

use std::env;
use libloading::{Library, Symbol};
use std::ffi::CString;
use std::os::raw::c_char;

type AddFunc = unsafe fn(i32, i32) -> i32;
type MsgFunc = unsafe fn(*const c_char, *mut *mut c_char);

fn main() {
    let library_path = env::args().nth(1).expect("USAGE: loading <LIB>");
    unsafe {
        let lib = Library::new(library_path).unwrap();
        let func: Symbol<AddFunc> = lib.get(b"add").unwrap();
        let answer = func(1, 2);
        println!("1 + 2 = {}", answer);

        let func2: Symbol<MsgFunc> = lib.get(b"echo2").unwrap();
        let message = CString::new("helloworld").unwrap();
        let mut message2: *mut c_char = 0x0 as *mut c_char;
        func2(message.as_ptr(), &mut message2);
        print!("{} => {}", message.to_str().unwrap(), CString::from_raw(message2).to_str().unwrap());
    }
}

C代码

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int add(int a, int b) {
    return a + b;
}

void echo(const char* input, char** output) {
    int len = strlen(input);
    *output = (char*)malloc(len + 1);
    for (int i = 0; i < len; i++) {
        (*output)[i] = input[i] + 1;
    }
    (*output)[len] = '\0';
}

void echo2(const char* input, char** output) {
    int len = strlen(input);
    *output = (char*)malloc(len + 1);
    for (int i = 0; i < len; i++) {
        (*output)[i] = toupper(input[i]);
    }
    (*output)[len] = '\0';
}

把C代码编译成动态链接库,其中-fPIC表示位置无关,-shared表示动态链接库

gcc -c -fPIC adder.c -o libadder.o
gcc -shared libadder.o -o libadder2.so

最后运行程序,得到结果如下

1 + 2 = 3
helloworld => HELLOWORLD

实际上rust代码之间也可以这样动态互调

#[no_mangle]
pub extern "C" fn add(a: isize, b: isize) -> isize {
    a + b
}

编译,cdynlib表示使用C ABI的动态链接库

rustc --crate-type cdylib adder.rs

Ref

  • https://www.michaelfbryan.com/rust-ffi-guide/dynamic_loading.html
  • https://github.com/nagisa/rust_libloading
  • https://man7.org/linux/man-pages/man3/dlopen.3.html
  • https://eli.thegreenplace.net/2012/08/24/plugins-in-c