go调用RUST

无参函数调用

先写一个rust的lib项目生成动态库

1
cargo new --lib embed
  • Cargo.toml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
[package]
name = "embed"
version = "0.1.0"
authors = ["k <2589788697@qq.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

[lib]
name = "embed"
crate-type = ["dylib"]
  • lib.rs
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
use std::thread;


#[no_mangle]
fn process(){
    let handles:Vec<_>=(0..=10).map(|_|{
        thread::spawn(||{
            let mut x = 0;
            for _ in 0..5000000{
                x += 1
            }
            x
        })
    }).collect();
    for h in handles{
        println!("thread finished with count={}",h.join().map_err(|_|"could not join a thread").unwrap());
    }

}
  • 编译 运行 cargo build --release得到libembed.dylib

将文件按照如下放置

1
2
3
4
5
6
7
8
9
├── Cargo.lock
├── Cargo.toml
├── src
│   ├── a.out
│   ├── interface.h
│   ├── lib.rs
│   ├── libembed.dylib
│   ├── main.c
│   └── test.go
  • interface.h
1
void process();
  • main.c
1
2
3
4
5
6
#include "interface.h"

int main(){
    process();
    return 0;
}
  • 编译运行C gcc main.c -L. -lembed && ./a.out PS:linux下编译gcc main.c -L. -lembed -Wl,-rpath=./ -Wl,-rpath=./用于指定程序运行寻找库的路径 运行结果
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
thread finished with count=5000000
thread finished with count=5000000
thread finished with count=5000000
thread finished with count=5000000
thread finished with count=5000000
thread finished with count=5000000
thread finished with count=5000000
thread finished with count=5000000
thread finished with count=5000000
thread finished with count=5000000
thread finished with count=5000000
  • test.go
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package main

/*
#cgo LDFLAGS: -L./ -lembed
#include "interface.h"
*/
import "C"

func main() {
	C.process()
}

go run test.go结果与C运行一致

有参函数调用

  • lib.rs
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#[repr(C)]
pub struct Test{
    a:u32,
    b:u32,
}


#[no_mangle]
pub extern "C" fn process(test:*const Test){
    unsafe{
        println!("{}",(*test).a);
        println!("{}",(*test).b)
    }

}

cargo build --release --out-dir . -Z unstable-options

  • main.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
struct Test
{
    int a;
    int b;
};


extern void process(struct Test *test);

int main(){
    struct Test test = {3,4};
    process(&test);
    return 0;
}

gcc main.c -L. -lembed -Wl,-rpath=./ && ./a.out

output

1
2
3
4
  • interface.h
1
2
3
4
5
6
typedef struct Test
{
    int a;
    int b;
} Test;
void process(struct Test *test);
  • test.go
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package main

/*
#cgo LDFLAGS: -L./ -lembed -Wl,-rpath=./
#include "interface.h" //非标准c头文件,所以用引号
typedef struct Test
{
    int a;
    int b;
} Test; #可以放但是不建议(建议放入interface.h)
*/
import "C"

func main() {
	test := C.Test{a: 3, b: 4}
	C.process(&test)
}

字符串指针返回

很多数据结构在跨语言调用,得在各个语言来回解析,比较麻烦,我们直接以json字符串传递解析可以极大的简化问题的处理

  • 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
use std::thread;
use libc::c_int;
use libc::c_char;
use std::ffi::{CStr,CString};
use json;




#[no_mangle]
pub extern "C" fn process(a:c_int){
    let handles:Vec<_>=(0..=10).map(|_|{
        thread::spawn(||{
            let mut x = 0;
            for _ in 0..5000000{
                x += 1
            }
            x
        })
    }).collect();
    for h in handles{
        println!("thread finished with count={}",h.join().map_err(|_|"could not join a thread").unwrap());
    }
    println!("{} have done",a)
}

#[no_mangle]
pub extern "C" fn json_parse(c_buf:*const c_char)-> *const c_char{
    let c_str = unsafe { CStr::from_ptr(c_buf) }.to_str().unwrap();
    let parsed = json::parse(c_str).unwrap();
    println!("{}",parsed["a"]);
    let data = r#"
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        }"#;
        CString::new(data).unwrap().into_raw()
}
  • main.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include "interface.h"
#include <stdio.h>

int main(){
    process(3);
    const char *str = "{\"a\": 3}";
    const char *ret_str = json_parse(str);
    printf("%s\n",ret_str);
    return 0;
}
  • interface.h
1
2
void process(int a);
const char * json_parse(const char *c_buf);
  • test.go
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package main

/*
#cgo LDFLAGS: -L./ -lembed
#include "interface.h" //非标准c头文件,所以用引号
*/
import "C"
import "fmt"

func main() {
	C.process(C.int(3))
	ret_ptr := C.json_parse(C.CString(`{"a":3}`))
	fmt.Println(C.GoString(ret_ptr))
}
Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackJimmy 设计