page contents

Rust引用自定义c/c++库

国内Rust相关的文章太少,无奈只能到github和Stack Overflow上找答案。这篇文章的内容其实是Rust FFI章节的相关知识,在这里做一下总结。

FFI

ffi指的是 foreign function interface(我理解为外部函数接口)
说白了就是rust调用c/c++和c/c++调用rust。不管是各类书籍和各类的教学文章里都已经写明了
他们改怎样做,这里我们也就不再啰嗦了。但是在编译、构建方面,提到的内容比较少,大部分是
使用rustc命令做编译链接(rustc -L /path/to/lib xxx.rs)。
涉及到cargo配置的很少很少。

在cargo book的Build Script里的Outputs of the Build Script一节,教我们如何配置build.rs来达到一些目的。在我最后做了一些尝试后,找到了在cargo管理的项目中,如何配置链接我们自定义的c/c++库文件

实践

首先准备好我们需要链接的库文件

    $ touch test.c

内容如下

    #include<stdio.h>
    void say_hello() 
    {
        printf("Hello Rust!\n");
    }

非常简单的一个函数,接下来我们把它编译成.a的静态库

    $ cc -c test.c -o test.o
    $ ar -r libtest.a test.o

接下来我们使用cargo创建一个新的Rust工程

    $ cargo new link_test --bin

这里给大家安利一下IDE,我目前在使用AndroidStudio + Rust插件。InterliJ IDEA + Rust插件应该也不错,没试过。但AndroidStudio就是基于它开发的。

编辑Cargo.toml 内容如下

    [package]
    name = "link_test"
    version = "0.1.0"
    authors = ["authors"]
    edition = "2018"
    
    build = "src/build.rs"
    
    [build-dependencies]
    dunce = "0.1.1"

在src目录中创建build.rs(放在其他目录下也可以需要在Cargo.toml中配置)

前方高能

build.rs内容如下:

    extern crate dunce;
    use std::{env, path::PathBuf};
    
    fn main() {
        let library_name = "test";
        let root = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
        let library_dir = dunce::canonicalize(root.join("src")).unwrap();
        println!("cargo:rustc-link-lib=static={}", library_name);
        println!("cargo:rustc-link-search=native={}", env::join_paths(&[library_dir]).unwrap().to_str().unwrap());
    }

主要是这两句:

    println!("cargo:rustc-link-lib=static={}", library_name);
    println!("cargo:rustc-link-search=native={}",env::join_paths(&[library_dir]).unwrap().to_str().unwrap());

第一句是告诉cargo,配置rustc库文件的类型和名称,类型这里我们写的是static因为用的是静态库还有dylib和framework可以选,但是使用dylib连接动态库我一直没有成功,有搞过的大佬希望可以指点一二(使用rustc --help命令可以查看更多内容)。第二句是告诉cargo,配置rustc库文件所在的目录

接下来把我们准备好的库文件丢到src目录下,来试试看我们的配置有没有效果,此时目录结构如下:

    |____Cargo.lock
    |____Cargo.toml
    |____src
    | |____build.rs
    | |____main.rs
    | |____libtest.a

打开我们的main.rs添加一下代码:

    fn main() {
        unsafe { say_hello(); }
    }

    #[link(name = "test", kind = "static")]
    extern "C" {
        pub fn say_hello();
    }

最后

    $ cargo run
    $ Hello Rust!
  • 发表于 2020-12-22 11:24
  • 阅读 ( 996 )
  • 分类:C/C++开发

0 条评论

请先 登录 后评论
Pack
Pack

1135 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1751 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章