Skip to content
FZQA edited this page Nov 27, 2018 · 9 revisions

golang的cgo支持调用C++的方法:extern "C"

c.h c.c封装了c++代码

https://www.cnblogs.com/sohoer2003/p/4329085.html

#pragma once

#ifdef __cplusplus
extern "C" {
#endif
void test();
#ifdef __cplusplus    
}
#endif 

需要被go调用的函数声明写入 extern "C"

package main
// #cgo LDFLAGS: -L . -lc_test -lstdc++ 
// #cgo CFLAGS: -I ./
// #include "c.h"
import "C"
  
func main(){      
    C.test()     
}

#cgo LDFLAGS:需要链接的库路径 #cgo CFLAGS: c文件所在位置

/*
#cgo LDFLAGS: -L/usr/local/lib -L../../build/src -lmyshare -lsnark -stdc++ -lgmp -lgmpxx
#cgo CFLAGS: -I ../
#include "wraplibsnark.hpp"
*/

-lsnark是libsnark的动态库 -lmyshare是封装接口后的动态库 -lgmp -lgmp++一定要加(原因在于内部引用类这两个库 可从cmakelist看出) (此方法来自云象 使用libsnark.so来自zokrates拷贝 源libsnark进行了修改 不适用于该项目开发)

目前将部分动态库拷贝至/usr/local/lib下 如运行go程序时提示找不到动态库,需要export LD_LIBRARY_PATH=/usr/local/lib命令行输入,此方法仅本次有效

该方法需修改cmakelist,将所有cmakelist.txt中static改为shared

/*
#cgo LDFLAGS: -L/usr/local/lib -lzk_wrap -lzm -lff -lsnark -lstdc++  -lgmp -lgmpxx
#include "../wraplibsnark.hpp"
*/

-lzk_wrap -lzm -lff -lsnark均需添加到/usr/local/lib中

c                  go   类型对比

char --> C.char --> byte 
signed char --> C.schar --> int8 
unsigned char --> C.uchar --> uint8 
short int --> C.short --> int16 
short unsigned int --> C.ushort --> uint16 
int --> C.int --> int 
unsigned int --> C.uint --> uint32 
long int --> C.long --> int32 or int64 
long unsigned int --> C.ulong --> uint32 or uint64 
long long int --> C.longlong --> int64 
long long unsigned int --> C.ulonglong --> uint64 
float --> C.float --> float32 
double --> C.double --> float64 
void * -> unsafe.Pointer
 C -> Go

int(C.int )    //普通类型这样

// C string to Go string
func C.GoString(*C.char) string    

// C string, length to Go string
func C.GoStringN(*C.char, C.int) string    

// C pointer, length to Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte
Go -> C

C.char
C.schar (signed char)
C.uchar (unsigned char)
C.short
C.ushort (unsigned short)
C.int
C.uint (unsigned int)
C.long
C.ulong (unsigned long)
C.longlong (long long)
C.ulonglong (unsigned long long)
C.float
C.double. 

unsafe.Pointer ----(void*)

// Go string to C string
func C.CString(string) *C.char

var val []byte
(*C.char)(unsafe.Pointer(&val[0]))

在我们以“C.*”的形式调用 C 语言代码库时,有一点需要特别注意。在 C 语言中,如果一个函数的参数是一个具有固定尺寸的数组, 那么实际上这个函数所需要的是指向这个数组的第一个元素的指针。C 编译器能够正确识别和处理这个调用惯例。它可以自行获取到这 个指针并传给函数。但是,这在我们使用 cgo 工具调用 C 语言代码库时是行不通的。在 Go 语言中,我们必须显式的将这个指向数 组的第一个元素的指针传递给C语言的函数,像这样:C.func1(&x[0])。

在 C 语言中没有像 Go 语言中独立的字符串类型。C 语言使用最后一个元素为‘\0’的字符数组来代表字符串。在 Go 语言的字符串和 C 语言的字符串之间进行转换的时候,我们就需要用到代码包 C 中的 C.CString、C.GoString 和 C.GoStringN 等函数。这些转换 操作是通过对字符串数据的拷贝来完成的。Go 语言内存管理器并不能感知此类内存分配操作。因为它们是由 C 语言代码引发的。所以, 我们在使用与 C.CString 函数类似的会导致内存分配操作的函数之后,需要调用代码包 C 的 free 函数以手动的释放内存。这里有 一个小技巧,即我们可以把对 C.free 函数的调用放到 defer 语句中或者放入在 defer 之后的匿名函数中。这样就可以保证在退出 当前函数之前释放这些被分配的内存了。

cs := C.CString(s) //Go 语言的字符串转换为了C语言的字符串 cs 变量的类型是 *C.Char defer C.free(unsafe.Pointer(cs))

如果想直接访问 C 语言中的 struct、union 或 enum 类型的话,就需要在名称前分别加入前缀 struct_、union 或 enum。比如, 我们需要在 Go 源码文件中访问C语言代码中的名为 command 的 struct 类型的话,就需要这样写:C.structcommand。那么,如果 我们想在Go语言代码中访问C语言类型struct中的字段需要怎样做呢?解决方案是,同样以 C 语言类型 struct 的实例名以及选择符“.” 作为前导,但需要在字段的名称前加入下划线“”。例如,如果 command1 是名为 command 的 C 语言 struct 类型的实例名,并且这 个类型中有一个名为 name 的字段,那么我们在 Go 语言代码中访问这个字段的方式就是command1._name。 需要注意的是,我们不能在 Go 的 struct 类型中嵌入 C 语言类型的字段。

标记 CFLAGS 可以指定用于 gcc 中的 C 编译器的选项。它常常用于指定头文件(.h 文件)的路径。 而标记 LDFLAGS 则可以指定 gcc 编译器会用到的一些优化参数,也可以用来告诉链接器需要用到的C语言代码库文件的位置。

1. 方案设计

VNT零知识设计方案

方案设计图

2. 方案实现

实现细节思考

2.1 libsnark模块实现

2.2 ethereum模块实现

2.3 cgo模块实现

3. 方案测试

部分问题

整体测试出的问题

3.1 libsnark模块测试

3.2 整体测试

4. 修改汇总

4.1 libsnark模块修改汇总

4.2 ethereum模块修改汇总

4.3 cgo模块修改汇总

5. 开发技巧

修改并编译web3.js文件

libsnark遇到的大“坑”

FZQA

CGO

MPT trie

transaction 部分修改

简易以太坊测试

Clone this wiki locally