最近,因为工作需要和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

到此结束