1. 程式人生 > >golang中使用cgo呼叫c++程式

golang中使用cgo呼叫c++程式

1 背景

這兩天在考慮使用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 來執行,很嫌棄這種,麻煩,所以自己就來該動了。自己專案中的程式碼就不能放在這了,原理都是相同的。

2 golang 呼叫c++ 例項

原始碼: 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 <math.h>
#include <iostream>

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 見文件說明。

3 其他例項

github原始碼中的exmapleTwo 是與以上例項類似的。只不過以上對c++類的包裝使用比上面更詳細。其中的temp也是從網上下載的原始碼。
更多cgo設定檔案include, lib的方式可以看看其他相關資料,此處懶得打字。