涉及问题
1)rust需要调用c生成的库(静态库和动态库)
2)c生成库时需要调用rust函数
3)同级目录下文件调用
4)主体代码调用builtins目录文件
5)builtins目录调用主体代码
6)builtins目录下文件生成库
7)生成多个bin文件
8)主体代码和builtins目录下文件重名(把其中一个文件名称换掉)
demo目录结构
lib目录:c静态库,
src目录: rust语言程序
variable目录:c动态库,
1 c生成库文件
1.1 生成静态库
使用命令:gcc -c xxx.c -o xxx.o
ar -r libxxx.a xxx.o
1.2 生成动态库
使用命令: gcc -fPIC -shared xxx.c -o libxxx.so
在生成c动态库时需要调用rust中实现的函数,只需要在c文件中使用extern
引入相应函数和定义,如下所示,aaaaa的实现在rust端。
1)rust代码
/* 供给c端代码使用,用于生成libxxx.a */
#[no_mangle] //不加[no_mangle]在c调用时可能会出现找不到aaaaa的情况
pub fn aaaaa()
{
println!("this is aaaaaa");
}
2)c代码
#include <stdio.h>
extern void aaaaa(void);
void builtins_variables_print()
{
aaaaa();
printf("this is builtins_variables function,");
}
2 c与rust间相互调用
2.1 c调用rust函数
参考1.2小节
2.2 rust调用C静态库
rust调用c静态库时需要再rust项目中添加build.rs
文件,该文件的作用是在编译代码的时候可以链接到库,相当于给rustc 添加编译参数。
1)c中代码的实现 ->生成名为r2c的库(libr2c.a)
#include <stdio.h>
#include <string.h>
int add(int i1, int i2) {
return i1+i2;
}
2)build.rs文件
extern crate dunce;
use std::{env, path::PathBuf};
fn main() {
let library_name_r = "r2c";
let root_r = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let library_dir_r = dunce::canonicalize(root_r.join("lib")).unwrap();
//主要是下面这两句
println!("cargo:rustc-link-lib=static={}", library_name_r); //相当链接的库
println!("cargo:rustc-link-search=native={}", env::join_paths(&[library_dir_r]).unwrap().to_str().unwrap()); //库路径
}
static:库类型
3)xxx.rs中使用c静态库方式
/* 使用C库 */
#[link(name = "r2c", kind = "static")] //链接的库
//c库中的函数
extern {
fn add(i1: c_int, i2: c_int) -> c_int;
fn replace(s: &mut [u8;3], d: &mut [u8;3]);
fn add_v2(i1: c_int, i2:c_int, out: &mut c_int);
}
/* c库使用实现 */
pub fn add_w(i1: i32, i2: i32) -> i32 {
unsafe {add(i1 as c_int, i2 as c_int)} //一定要加unsafe,否则会报错
}
2.3 rust调用c动态库
同样需要build.rs
文件。
1)c中代码的实现 ->生成名为builtins_variable的库(libbuiltins_variable.so)
#include <stdio.h>
extern void aaaaa(void);
void builtins_variables_print()
{
aaaaa();
printf("this is builtins_variables function,");
}
2)build.rs文件
extern crate dunce;
use std::{env, path::PathBuf};
fn main() {
let root_v = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let library_dir_v = dunce::canonicalize(root_v.join("variable")).unwrap();
//库文件路径,与静态链接的区别是没有加库名称
println!("cargo:rustc-link-search=native={}", env::join_paths(&[library_dir_v]).unwrap().to_str().unwrap());
}
3)xxx.rs中使用c动态库方式
/* 使用c端动态库 */
#[link(name = "builtins_variables")] //动态库只需要写动态库的名称
extern "C" {
fn builtins_variables_print();
}
pub unsafe fn b_print()
{
println!("this is src/b.rs");
println!("使用c动态库");
builtins_variables_print(); //实现位置:c动态库
}
3 rust项目中不同目录下文件的相互 调用
文件相互引用的时候,需要再在src目录下添加lib.rs
文件,lib.rs
添加在src目录下时与和src同级目录时使用方式不同。本文选择在src目录下的方式,于src同级的没研究明白。(不清楚不使用lib可不可以)
好像所有文件的引用都可以使用include
宏,当不同文件中有相同函数名称时貌似不能使用。使用inclued宏的时候引用那个文件中的哪些函数是不需要写的。
lib.rs内容
以下3中情况的lib.rs
内容相同。
pub mod builtins{ //builtin中的内容添加得到下面
pub mod ffi_wrapper;
pub mod a;
pub mod b;
}
3.1 同级目录
3.1.1 builtins目录下文件相互引用
a.rs
和b.rs
都为builtins目录下文件
1) a.rs内容
pub fn a_print(){ //不加pub应该是引用不到
println!("this is builtins/a");
}
2) b.rs内容
/* b.rs调用a.rs中函数 */
use crate::builtins::a::{a_print}; //lib.rs存放位置这不同,这个位置的引用方式应该不同
//include!(concat!("a.rs")); //也可以使用include的方式,之前怎么没发现呢,直到写文档才想起来
pub fn b_print()
{
a_print(); //使用a.rs
println!("this is builtins/b");
}
3.1.2 src目录下文件相互引用
src目录下内容相互引用是用include!
宏,使用方式为include!(concat!("xxx.rs"));
f.rs
引用e.rs
文件内容。f.rs
、e.rs
同在src目录下
1)e.rs内容
pub fn e_print()
{
println!("this is e");
}
2)f.rs内容
include!(concat!("e.rs"));
pub fn f_print()
{
println!("this is f");
e_print();
}
3)main.rs引用同级目录
#![allow(
mutable_transmutes,
non_camel_case_types,
non_snake_case,
non_upper_case_globals,
unused_assignments,
unused_mut,
unused_must_use
)] //警告
/* 使用src/b.rs */
mod b;
use crate::b::{b_print}; //在builtins目录下的b.rs文件中也有一个b_print的函数,用这种方式可以区分引用的是哪个,下面的include的方式貌似不可以。一般也不会出现这种情况
// include!(concat!("./b.rs"));
fn main() {
unsafe { b_print() };
}
3.2 子目录引用上层目录
这种情况也是使用include!
的形式
在buildints\b.rs
使用src\f.rs
中函数
1)buildints\b.rs内容
/* b.rs调用src/f.rs中函数 */
include!(concat!("../f.rs"));
pub fn b_print()
{
f_print(); //使用f.rs
println!("this is builtins/b");
}
2) src\f.rs内容
include!(concat!("e.rs"));
pub fn f_print()
{
println!("this is f");
e_print();
}
3.3 上层目录引用子目录
src\c.rs
引用builtins\b.rs
中函数
1)builtins\b.rs内容
/* b.rs调用a.rs中函数 */
// use crate::builtins::a::{a_print};
include!(concat!("a.rs"));
/* b.rs调用src/f.rs中函数 */
include!(concat!("../f.rs"));
pub fn b_print()
{
a_print(); //使用a.rs
f_print(); //使用f.rs
println!("this is builtins/b");
}
2)src\c.rs内容
/* c.rs调用builtins/b.rs中函数 下面两种方式都可以*/
// pub use builtins::builtins::b::{b_print};
include!(concat!("./builtins/b.rs"));
pub fn c_print()
{
b_print();
println!("this is c");
}
4 creat生成bin和lib
一个creat只可以生成一个lib文件(lib的类型可以是多种);但是可以生成多个bin文件。只需要配置Cargo.toml
文件即可。
1)Cargo.toml内容
[package] # 包信息
name = "r2c" # 名称
version = "0.1.0" # 版本
authors = ["yxhl"] # 作者
edition = "2018"
build = "./build.rs" # 编译配置文件
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
# 依赖
[dependencies]
libc = "*"
# 编译依赖
[build_dependencies]
dunce = "1.0.0"
# 生成的库信息
[lib]
name = "builtins" # 库名称
path = "src/lib.rs" # 生成库的文件
crate-type = ["staticlib","rlib"] # 生成的库类型,静态库和rust库
# 生成的二进制,可以是多个,main函数自动会生成一个和package同名的bin文件
[[bin]]
name = "utshell" # 二进制名称
path = "src/a.rs" # 生成二进制使用的文件
bin文件也可以写在bin目录下吧