因工作需求,需要将一个工具由终端行的运行方式迁移到 web 上,核心代码由 c++ 动态库实现,另一部门的同事使用 Java 实现了一个版本,部门同事安排我做部署,由于服务器是离线的,且由专人管理,JDK 和 Tomcat 安装稍麻烦,个人操作自由度不够,——一是没有研究过 Java,二来部署麻烦。因此,决定使用 Golang 实现。预计展开的内容有:Golang 调用 C++ 动态库;Golang Web 服务及整合 html/css资源;(大)前端框架使用。
本文主要研究 C++ 动态库及函数的调用。
思路
Golang 只支持 C 语言的编译,对于 C++ 的编译,有2种方法: 1、不使用类,在 C++ 代码头文件添加extern "C" {,将函数声明为 C 格式。 2、如出现类的情况,再用另外的文件将其封装成 C 格式函数。
// 简单函数调用 cstr := C.CString("call C func") defer C.free(unsafe.Pointer(cstr)) var i C.int i = 100 C.FooSetValue(i, C.uint(250), C.float(3.14159), cstr) C.PrintString(cstr);
源码要点如下: 1、需设置编译参数 LDFLAGS,指定库位置和名称,本例中是当前目录的 libfoo.so。 2、需包含相应的头文件,stdlib.h 为 free 函数所在文件。 3、内嵌的 C 源码在包的前面,且import "C"后需空一行。 4、传递到 C 函数的内存,使用C.CString申请,C 申请的内存使用C.GoString获取,均需要手动释放。
结果分析
在运行前,需要设置动态库路径:
1
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
否则运行时无法找到动态库:
1
./test: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory
运行结果如下:
1 2 3 4 5 6 7 8 9 10 11 12
go c++ so test C++ | base type: 100 250 3.1416 call C func C++ | string = call C func Golang | org struct {100 200 [72 101 108 108 32 0 0 0 0 0 0 0 0 0 0 0] 0x25b2a30 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] <nil>} single: 100 200 0x25b2a30 C++ | the point in c for value: 100 200 C++ | got buf: Hell C++ | pname: Hello C++ | ptr: 0x25b2a50 Golang | c++ call ret: 0 101 name in c++ [110 97 109 101 32 105 110 32 99 43 43 0 0 0 0 0] Golang | out pointer: Hell | name in c++ malloc 0x25b2a50 C++ Class | Bar(): num: 250 C++ Class | Bar(): num: 250
从上述结果中可看出,C 中申请的内存,其指针与在 Go 中获取的指针是一样的,即 0x25b2a50。结构体中的 nil 是因为字段 pname 未赋值。
# command-line-arguments In file included from ./bar.cpp:2:0, from ./main_one.go:17: ./foo.h:6:1: error: unknown type name 'class' class CFoo ^ ./foo.h:7:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token { ^ In file included from ./main_one.go:17:0: ./bar.cpp: In function 'FooCall1': ./bar.cpp:18:5: error: unknown type name 'CFoo' CFoo * ret = new CFoo(num); ^ ./bar.cpp:18:18: error: 'new' undeclared (first use in this function) CFoo * ret = new CFoo(num); ^ ./bar.cpp:18:18: note: each undeclared identifier is reported only once for each function it appears in ./bar.cpp:18:22: error: expected ',' or ';' before 'CFoo' CFoo * ret = new CFoo(num); ^ ./bar.cpp:19:8: error: request for member 'Bar' in something not a structure or union ret->Bar();