最近,因为工作需要和C/C++语言打交道。用 Go 的 cgo 去掉用他们编写好的静态库,因为,C/C++ 不是我的熟悉开发语言。比较曲折暂时还在研究中
准备条件
- Window 10
- Rust 1.38.x
- Go 1.13.x
注意使用 Rust 和 Go 的cgo 需要安装 Window C 开发依赖 Visual C++ Build Tools 这个就请自行搜索吧
依赖库
Rust - cbindgen = “^0.11.0” 自动帮我们生成C的头文件.h
Go 没有依赖
代码
Cargo.tml
[package]
build = "build.rs" 配置编译头文件编译内容
[dependencies]
[lib]
crate-type = ["cdylib"] 配置为动态库模式
[build-dependencies]
cbindgen = "^0.11.0"
cbindgen.toml 配置生成规则
header = ""
tab_width = 4
language = "C"
Rust 代码
build.rs
extern crate cbindgen;
fn main() {
let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
cbindgen::generate(crate_dir)
.expect("Unable to generate C bindings.")
.write_to_file("target/incloud/add.h");
}
lib.rs 需要引用的方法
#![crate_type = "lib"]
#[no_mangle]
pub extern "C" fn add(value1: u32, value2: u32) -> u32 {
println!("rust_lib: rust_add !");
value1 + value2
}
生成头文件内容案例:
/*
Gutengerg Post Parser, the C bindings.
Warning, this file is autogenerated by `cbindgen`.
Do not modify this manually.
*/
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
uint32_t add(uint32_t value1, uint32_t value2);
我们自己手写写成这样也是可以使用的
extern int add(int a,int b);
是不是更简单啊
Go 代码
需要注意以下配置内容 #cgo CFLAGS: -Iinclude 头文件引用目录 #cgo LDFLAGS: -Llib -llibvideo dll 目录 #include “add.h” 引用头文件
package main
/*
#cgo CFLAGS: -Iinclude
#cgo LDFLAGS: -Llib -llibvideo
#include "video.h"
*/
import "C"
import (
"fmt"
"syscall"
)
func abort(funcname string, err error) {
panic(funcname + " failed: " + err.Error())
}
func GoSum(a, b int) {
h, err := syscall.LoadLibrary("./lib/add.dll")
if err != nil {
abort("LoadLibrary", err)
}
defer syscall.FreeLibrary(h)
add, err := syscall.GetProcAddress(h, "add")
if err != nil {
abort("add", err)
}
r, _, _ := syscall.Syscall(uintptr(add), 1, uintptr(a), uintptr(b), 4)
fmt.Println(uint32(r))
}
func main() {
GoSum(4, 5)
}
运行方式
必须先构建,在运行。直接 go run 和 编辑器里面 运行都会说加载不到 dll
go build -v
在运行对应的生成文件,看到如下内容就证明运行成功啊
rust_lib: rust_add !
9
到此结束