这两天在考虑使用golang搭建一个http服务,调用别人的linux sdk。由于linux sdk是用c写的,直接使用cgo调用c是很方便的,但是个人想使用c++来调用c的函数,封装成c++语法,c++可以使用一些库,对于开发是比较方便的,所以就得考虑使用cgo调用c++程序。
网上一搜,目前实现cgo调用c++主要有三种方式:
1 swig
2 swift
3 使用c包装c++,然后cgo调用c
对于以上3种方式,第2种我是没看过,第1种就浏览了下,没写过。主要是想用第3种,可以纯粹的写c++,c。
环境:
ubuntu 16 64bit (个人喜欢用centos 7.*)
gcc g++都是默认的。
golang gopath = /home/user/gopath
说明:以下代码是从网上下载的,但是别人的实现是要编译可执行文件,即go build, 然后执行可执行文件。(源码地址:draffensperger/go-interlang )不能通过go run *.go 来执行,很嫌弃这种,麻烦,所以自己就来该动了。自己项目中的代码就不能放在这了,原理都是相同的。
源码: example
目录结构:
exampleOne 一定要放在src中,防止找不到包
$gopath:
src - exampleOne
- main.go
- temp
- one.go, point.cxx point.hxx wrap_point.cxx wrap_point.hxx
temp中是从网上下的源码,不作改动。
然后就可以执行:
go run main.go
文件与代码:
main.go
// main.go
package main
import (
"funcExample/temp"
)
func main () {
temp.P()
}
temp 下的 one.go
// one.go
package temp
// #include "wrap_point.hxx"
import "C"
import "fmt"
func init() {
fmt.Println("Hi from Go, about to calculate distance in C++ ...")
distance := C.distance_between(1.0, 1.0, 2.0, 2.0)
fmt.Printf("Go has result, distance is: %v\n", distance)
}
func P() {
distance := C.distance_between(1.0, 1.0, 2.0, 2.0)
fmt.Println(distance)
}
temp下的 point.cxx
// point.cxx
#include "point.hxx"
#include
#include
Point::Point(double x, double y): x_(x), y_(y) {
}
double Point::distance_to(Point p) {
std::cout << "C++ says: finding distance between (" << x_ << "," << y_
<< "), and (" << p.x_ << "," << p.y_ << ")" << std::endl;
double x_dist = x_ - p.x_;
double y_dist = y_ - p.y_;
return sqrt(x_dist * x_dist + y_dist * y_dist);
}
temp 下的 point.hxx
// point.hxx
#ifndef POINT_H
#define POINT_H
class Point {
public:
Point(double x, double y);
double distance_to(Point p);
private:
double x_, y_;
};
#endif
temp 下的wrap_point.cxx
// wrap_point.cxx
#include "wrap_point.hxx"
#include "point.hxx"
double distance_between(double x1, double y1, double x2, double y2) {
return Point(x1, y1).distance_to(Point(x2, y2));
}
temp 下的 wrap_point.hxx
// wrap_point.hxx
#ifndef WRAP_POINT_H
#define WRAP_POINT_H
// __cplusplus gets defined when a C++ compiler processes the file
#ifdef __cplusplus
// extern "C" is needed so the C++ compiler exports the symbols without name
// manging.
extern "C" {
#endif
double distance_between(double x1, double y1, double x2, double y2);
#ifdef __cplusplus
}
#endif
#endif
对于以上的代码自己不做过多说明,都是c/c++ 的用法。
关于cgo语法类型与c的对应关系,可以直接查看cgo文档 command cgo,cgo除了提供直接与c数据类型的对应类型,还支持使用函数将golang数据类型转换成c的数据类型,比如 func C.CString(string) *C.char
见文档说明。
github源码中的exmapleTwo 是与以上实例类似的。只不过以上对c++类的包装使用比上面更详细。其中的temp也是从网上下载的源码。
更多cgo设置文件include, lib的方式可以看看其他相关资料,此处懒得打字。