CGO
Home
启用CGO特性
package main
import "C"
func main() {
//
}
- 通过
import "C"
启用 CGO 特性,在go build
时在编译和连接阶段启动 gcc 编译器。- CGO 会将
import "C"
语句上一行代码所处注释块的内容视为 C 代码块,被称为序文(preamble)。
Go 调用 C
qkd.go
/*
#cgo CFLAGS: -I./include
#cgo LDFLAGS: -L/app/lib -lkeyout -lstdc++ -lm
#include "KeyReadAPI.h"
void callbackFunc(uint32_t command, void *data); // 定义的 C 函数
*/
import "C"
ℹ️
#cgo CFLAGS: -I./include
: 编译参数,主要是头文件的检索路径。#cgo LDFLAGS: -L/app/lib -lkeyout -lstdc++ -lm
: 链接参数:指定要链接库(静态库.a文件
或动态库.so文件
)的检索目录和要链接库的名字(注意是否区分大小写),不支持相对路径。#include "KeyReadAPI.h"
: 包含的头文件,查找位置通过cgo CFLAGS: -I./include
指定
查看KeyReadAPI.h
KeyReadAPI.h
int auth_login(const char *config_path);
void register_data_func(pfunc_process_data p_user_function);
int read_key(uint32_t peer_dev_info,uint32_t key_read_id, uint32_t key_apply_len,
uint8_t *quantum_key,uint32_t *quantum_key_len);
typedef void (*pfunc_process_data)(uint32_t command, void *data); // 定义的回调函数,register_data_func注册该回调函数
void callbackFunc(uint32_t command, void *data)
中void *data
对应的 c++ 中定义的结构体。
KeyReadAPI.h
typedef struct
{
uint32_t key_read_id; //密钥读取标示
uint32_t key_len; //本次输出的密钥量
uint8_t key_data[512*1024]; //密钥数据
} st_key_push_data;
定义接口
qkd.go
type QkdService interface {
// AuthLogin 设备入网
AuthLogin() error
// RegisterDataFunc 被动端用户函数注册
RegisterDataFunc()
// ReadKey 主动端密钥申请
ReadKey() error
}
定义结构体,实现接口并通过C.
调用C代码
qkd.go
type qkdService struct {
config *config.Config
}
const configPath = "/app/KeyOutLibConfig.xml"
const (
keyBufferLen = 0 // 量子密钥缓存实际长度
keyApplyLen = 1024 // 一次请求的密钥量,单位Byte,只支持1024的整数倍,上限512*1024
)
var keyQueue = &KeyQueue{
key: make([]string, 0),
}
type KeyQueue struct {
key []string
}
func (k *KeyQueue) Enqueue(key string) {
log.Debug().Msgf("Qkd密钥入队列,key is %s", key)
k.key = append(k.key, key)
}
func (k *KeyQueue) Dequeue() (key string, err error) {
if len(k.key) == 0 {
return "", errors.New("")
}
key = k.key[0]
k.key = k.key[1:]
return key, nil
}
func (svc *qkdService) AuthLogin() error {
path := C.CString(configPath)
//defer C.free(unsafe.Pointer(path))
code := int(C.auth_login(path))
if code == Success {
return nil
}
errMsg, ok := qkdErrMsgGroup[qkdErrorCode(code)]
if ok {
return errors.New(errMsg)
}
return errors.New("QKD Auth Login接口未知异常")
}
func (svc *qkdService) RegisterDataFunc() {
C.register_data_func(C.pfunc_process_data(C.callbackFunc))
}
func (svc *qkdService) ReadKey() error {
var peerDevId = svc.config.Qkd.DevId // 被动端应用设备ID,配置文件值KSP ID
var keyReadId = rand.Uint32() // 密钥读取标示,可用于标识读取次数,每次密钥申请此参数不能重复。
keyBuffer := make([]uint8, 512*1024) // 量子密钥数据缓存
cKeyBuffer := (*C.uint8_t)(unsafe.Pointer(&keyBuffer[0]))
cKeyBufferLen := new(uint32)
*cKeyBufferLen = 0
cKeyBufferLenPtr := (*C.uint32_t)(unsafe.Pointer(cKeyBufferLen))
code := int(C.read_key(C.uint32_t(peerDevId), C.uint32_t(keyReadId), C.uint32_t(keyApplyLen), cKeyBuffer, cKeyBufferLenPtr))
if code != 0 {
msg, ok := qkdErrMsgGroup[qkdErrorCode(code)]
if ok {
return errors.New(msg)
} else {
return errors.New("未知异常")
}
}
return nil
}
C 调用 Go
C references to Go
Go functions can be exported for use by C code in the following way:
//export MyFunction
func MyFunction(arg1, arg2 int, arg3 string) int64 {...}
//export MyFunction2
func MyFunction2(arg1, arg2 int, arg3 string) (int64, *C.char) {...}
They will be available in the C code as:
extern GoInt64 MyFunction(int arg1, int arg2, GoString arg3);
extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3);
Not all Go types can be mapped to C types in a useful way. Go struct types are not supported; use a C struct type. Go array types are not supported; use a C pointer.
编译选项
目录结构
- qkd.go
- KeyReadAPI.h
- libkeyout.a
qkd.go
代码
qkd.go
/*
#cgo CFLAGS: -I./include
#cgo LDFLAGS: -L/app/lib -lkeyout -lstdc++ -lm
#include "KeyReadAPI.h"
void callbackFunc(uint32_t command, void *data); // 定义的 C 函数
*/
import "C"
-lstdc++
表示链接 C++ 标准库;-lm
表示链接数学库(libm.a 或 libm.so);
最后更新于