C++如何调用rust源码代码
关于rust库工程与上一篇相同,重点是C++主工程部分
一.rust库工程
1.创建rust库工程
创建rust_lib库工程,工程目录如下
rust_lib
—src
——lib.rs
—Cargo.toml
—Cargo.lock
2.build.rs文件创建与配置
build.rs创建
1
2
3
4
5
6
7
8
9
10
11
12
13
|
extern crate cbindgen;
use std::env;
fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
cbindgen::Builder::new()
.with_crate(crate_dir)
.generate()
.expect("Unable to generate bindings")
.write_to_file("rust_lib.h");//生成头文件名称
}
|
build.rs配置
build.rs,用来在编译期间,生成rust库导出的.h头文件,工程目录如下
rust_lib
—src
——lib.rs
—Cargo.toml
—Cargo.lock
—build.rs
然后在Cargo.toml文件中,配置build.rs文件
1
2
3
4
5
6
|
[package]
name = "rust_lib"
version = "0.1.0"
edition = "2021"
#新增编译期间生成rust库导出的.h头文件
build = "build.rs"
|
3.Cargo.toml配置
1
2
3
4
5
6
7
8
|
[lib]
# 生成动态库
#crate-type = ["cdylib"]
# 生成静态库
crate-type = ["staticlib"]
[build-dependencies]
cbindgen = "0.25.0"
|
3.添加rust库导出类及函数
lib.rs内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
use std::os::raw::c_char;
// 使用 C 语言的结构体布局
#[repr(C)]
pub struct MyStruct {
pub name: *const c_char,
pub age: i32,
}
#[no_mangle]
pub extern "C" fn create_my_struct( name: *const c_char, age: i32,) -> *mut MyStruct {
Box::into_raw(Box::new(MyStruct { name, age }))
}
#[no_mangle]
pub extern "C" fn get_age_from_struct(ptr: *const MyStruct) -> i32 {
unsafe {
(*ptr).age
}
}
#[no_mangle]
pub extern "C" fn get_name_from_struct(ptr: *const MyStruct) -> *const c_char {
unsafe {
(*ptr).name
}
}
// 释放内存的函数
#[no_mangle]
pub extern "C" fn free_my_struct(ptr: *mut MyStruct) {
unsafe {
if !ptr.is_null() {
let _ = Box::from_raw(ptr);
}
}
}
// 在 Rust 中定义一个简单的函数
#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {
return a + b
}
|
4.生成静态库
使用cargo build生成debug版本库,如果是release版本,使用cargo build –release命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
lvwei@lvweideMacBook-Pro rust_lib % cargo build
Compiling rust_lib v0.1.0 (/Users/lvwei/Documents/clion_cpp_demo/rust_lib)
Finished dev [unoptimized + debuginfo] target(s) in 0.79s
#
lvwei@lvweideMacBook-Pro rust_lib % cargo build --release
Compiling proc-macro2 v1.0.78
Compiling unicode-ident v1.0.12
Compiling libc v0.2.152
Compiling autocfg v1.1.0
Compiling serde v1.0.195
Compiling rustix v0.38.30
Compiling os_str_bytes v6.6.1
Compiling syn v1.0.109
Compiling hashbrown v0.12.3
Compiling serde_json v1.0.111
Compiling indexmap v1.9.3
Compiling bitflags v2.4.2
Compiling clap_lex v0.2.4
Compiling itoa v1.0.10
Compiling ryu v1.0.16
Compiling cfg-if v1.0.0
Compiling fastrand v2.0.1
Compiling termcolor v1.4.1
Compiling textwrap v0.16.0
Compiling bitflags v1.3.2
Compiling cbindgen v0.25.0
Compiling strsim v0.10.0
Compiling log v0.4.20
Compiling heck v0.4.1
Compiling errno v0.3.8
Compiling atty v0.2.14
Compiling clap v3.2.25
Compiling tempfile v3.9.0
Compiling quote v1.0.35
Compiling syn v2.0.48
Compiling serde_derive v1.0.195
Compiling toml v0.5.11
Compiling rust_lib v0.1.0 (/Users/lvwei/Documents/clion_cpp_demo/rust_lib)
Finished release [optimized] target(s) in 10.22s
|
二.C++工程
1.创建C++工程
创建cppcallrustproject工程,把rust库头文件和动态库放到rust_lib目录,静态库放到rust_static_lib目录,
工程目录如下
cppcallrustproject
—rust_lib
——output
——–include
———–rust_lib.h
——lib
———debug
————librust_lib.a
————librust_lib.dylib
——src
———lib.rs
——target
——build.rs
——cargo.lock
——cargo.toml
—CMakeLists.txt
—main.cpp
2.CMakeLists.txt配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
cmake_minimum_required(VERSION 3.26)
project(cppcallrustproject)
set(CMAKE_CXX_STANDARD 14)
# cargo编译 Rust 项目
execute_process(
COMMAND cargo build
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/rust_lib#rust代码库目录
)
add_executable(${PROJECT_NAME} main.cpp)
# 设置 Rust 项目的输出路径
set(RUST_WORK_DIR ${CMAKE_SOURCE_DIR}/rust_lib)
set(RUST_LIB_DIR ${RUST_WORK_DIR}/target)
set(RUST_LIB_OUTPUT_DIR ${RUST_WORK_DIR}/output/lib)
#SHARED OR STATIC 记得同步切换cargo.toml文件中的库类型
set(LIB_TYPE "STATIC")
# 检查是否为调试版本还是发布版本
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
if (LIB_TYPE STREQUAL "STATIC")
set(RUST_LIB ${RUST_WORK_DIR}/target/debug/librust_lib.a)
else ()
set(RUST_LIB ${RUST_WORK_DIR}/target/debug/librust_lib.dylib)
endif ()
else()
if (LIB_TYPE STREQUAL "STATIC")
set(RUST_LIB ${RUST_WORK_DIR}/target/release/librust_lib.a)
else ()
set(RUST_LIB ${RUST_WORK_DIR}/target/release/librust_lib.dylib)
endif ()
endif()
# 如果变量的值为 static,则执行静态逻辑
if(LIB_TYPE STREQUAL "STATIC")
add_library(rust_lib STATIC IMPORTED)
# 执行静态逻辑的代码
else()
add_library(rust_lib SHARED IMPORTED)
endif()
message("LIB_TYPE:" ${LIB_TYPE})
set_property(TARGET rust_lib PROPERTY IMPORTED_LOCATION ${RUST_LIB})
target_link_libraries(${PROJECT_NAME} rust_lib)
# 拷贝llib到RUST_WORK_DIR目录
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
if(LIB_TYPE STREQUAL "STATIC")
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${RUST_LIB_DIR}/debug/librust_lib.a
${RUST_LIB_OUTPUT_DIR}/debug/librust_lib.a)
else ()
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${RUST_LIB_DIR}/debug/librust_lib.dylib
${RUST_LIB_OUTPUT_DIR}/debug/librust_lib.dylib)
endif ()
else()
if(LIB_TYPE STREQUAL "STATIC")
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${RUST_LIB_DIR}/release/librust_lib.a
${RUST_LIB_OUTPUT_DIR}/release/librust_lib.a)
else ()
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${RUST_LIB_DIR}/release/librust_lib.dylib
${RUST_LIB_OUTPUT_DIR}/release/librust_lib.dylib)
endif ()
endif()
|
2.rust_lib.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#include <cstdarg>
#include <cstdint>
#include <cstdlib>
#include <ostream>
#include <new>
extern "C" {
struct MyStruct {
const char *name;
int32_t age;
};
MyStruct *create_my_struct(const char *name, int32_t age);
int32_t get_age_from_struct(const MyStruct *ptr);
const char *get_name_from_struct(const MyStruct *ptr);
void free_my_struct(MyStruct *ptr);
int32_t add(int32_t a, int32_t b);
} // extern "C"
|
3.main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#include <iostream>
#include "rust_lib.h"
int main() {
std::cout << "Hello, World!" << std::endl;
int res = add(10, 20);
std::cout << "10 + 20=" << res << std::endl;
const char* name = "ksnowlv write cpp call Rust!";
MyStruct* myStruct = create_my_struct(name, res);
if (myStruct) {
std::cout << "age: " << get_age_from_struct(myStruct) << std::endl;
std::cout << "name: " << get_name_from_struct(myStruct) << std::endl;
free_my_struct(myStruct);
}
return 0;
}
|
4.执行情况
文章作者
梵梵爸
上次更新
2024-01-23
许可协议
原创文章,如需转载请注明文章作者和出处。谢谢