calling c++ from golang with swig--windows dll

之前项目组开发的项目核心代码全部使用C++语言,新项目可能会引入golang,花了一天多时间研究了windows环境下golang调用C++动态链接库的方法。

谷歌加百度之后,很快发现官方推荐的方法,在官方FAQ页面可以找到答案:

https://golang.org/doc/faq

Do Go programs link with C/C++ programs?

There are two Go compiler implementations, gc and gccgo. Gc uses a different calling convention and linker and can therefore only be linked with C programs using the same convention. There is such a C compiler but no C++ compiler. Gccgo is a GCC front-end that can, with care, be linked with GCC-compiled C or C++ programs.

The cgo program provides the mechanism for a “foreign function interface” to allow safe calling of C libraries from Go code. SWIG extends this capability to C++ libraries.

上文的大意是:golang有两个编译器实现,gc和gccgo。gc编译器使用一个不同的调用约定和链接器,因此只能链接使用相同约定的C程序;gccgo是一个GCC的前端,可以链接GCC编译的C和C++程序。cgo程序提供了一个“外部函数接口”机制,允许在Golang中安全地调用C库。SWIG扩展了这个能力,使得Golang可以调用C++库。

由官方的问答可以知道,如果Golang要调用C++库,需要借助gccgo和swig。

SWIG 是一个非常优秀的开源工具,支持您将 C/C++ 代码与任何主流脚本语言相集成。SWIG的一个入门介绍可以参考《开发人员 SWIG 快速入门》

http://www.ibm.com/developerworks/cn/aix/library/au-swig/

SWIG官方网址 http://www.swig.org/

Github上的开源代码仓库: https://github.com/swig/swig

从github上看介绍,swig支持很多种语言:

SWIG is a compiler that integrates C and C++ with languages

including Perl, Python, Tcl, Ruby, PHP, Java, C#, D, Go, Lua,Octave, R, Scheme (Guile, MzScheme/Racket, CHICKEN), Scilab, Ocaml, Modula-3, Common Lisp (CLISP, Allegro CL, CFFI, UFFI) and Pike. SWIG can also export its parse tree into XML and Lisp s-expressions.

Swig最新的发布版本是2017年1月28日发布的rel-3.0.12。

在Github上下载的发布包没有预编译的swig.exe;自己编译比较麻烦,所以直接从http://www.swig.org/download.html 页面下载最新发布包,

根据提示,从第二个链接下载,包含了预编译的可执行程序。

解压缩后,文件夹下有swig.exe,后面会看到需要借助这个工具生成代码。Golang借助swig调用C++还是非常简单的,看下Examples/go目录下的示例就可以入门了。

用浏览器打开Examples\go\index.html看下文字说明,

  • When using the gccgo compiler, the steps look like this:

% swig -go -cgo interface.i

% mkdir -p gopath/src/interface

% cp interface_wrap.c interface_wrap.h interface.go gopath/src/interface

% GOPATH=`pwd`/gopath

% export GOPATH

% cd gopath/src/interface

% go build

% gccgo -c $(SRCDIR)/runme.go

% gccgo -o runme runme.o interface.a

这个文档介绍的使用说明与软件版本不太相符,文档更新落后软件太多。实际上只要一条命令就可以了。下面来介绍下go借助swig调用C++的方法,以Examples\go\class为例:

(我的电脑是windows 7 X64,golang也是64位)

将下载的swigwin-3.0.12.zip包解压到D盘,然后将D:\swigwin-3.0.12\swig.exe加入环境变量。

打开cmd,工作目录切换到D:\swigwin-3.0.12\Examples\go\class

执行命令 swig -c++ -cgo -go -intgosize 64  example.i

成功执行后在D:\swigwin-3.0.12\Examples\go\class生成两个文件,example.go和example_wrap.cxx,这两个文件便是是在go中调用的包,runme.go属于main包,golang只运行一个文件夹对应一个包,所以需要在D:\swigwin-3.0.12\Examples\go\class下创建example子文件夹,将example.go和example_wrap.cxx、class.cxx、example.h四个文件移动到D:\swigwin-3.0.12\Examples\go\class\example路径下。

命令行中执行go build, 编译成功后,在D:\swigwin-3.0.12\Examples\go\class文件夹中生成class.exe,执行class.exe输出如下内容:

回过头来看下详细的开发步骤。

首先编写供golang调用的c++源文件,

example.h和class.cxx

/* File : example.h */

class Shape {

public:

Shape() {

nshapes++;

}

virtual ~Shape() {

nshapes--;

}

double  x, y;

void    move(double dx, double dy);

virtual double area() = 0;

virtual double perimeter() = 0;

static  int nshapes;

};

class Circle : public Shape {

private:

double radius;

public:

Circle(double r) : radius(r) { }

virtual double area();

virtual double perimeter();

};

class Square : public Shape {

private:

double width;

public:

Square(double w) : width(w) { }

virtual double area();

virtual double perimeter();

};

该头文件包含了一个基类和两个派生类的声明。

class.cxx包含了对应的源码实现:

/* File : class.cxx */

#include "example.h"

#define M_PI 3.14159265358979323846

/* Move the shape to a new location */

void Shape::move(double dx, double dy) {

x += dx;

y += dy;

}

int Shape::nshapes = 0;

double Circle::area() {

return M_PI*radius*radius;

}

double Circle::perimeter() {

return 2*M_PI*radius;

}

double Square::area() {

return width*width;

}

double Square::perimeter() {

return 4*width;

}

接下来需要定义swig工具生成代码需要的输入文件example.i,只需指定包名和包含的c++头文件,相当简单。

/* File : example.i */

%module example

%{

#include "example.h"

%}

/* Let's just grab the original header file here */

%include "example.h"

接下来就是在命令行中输入swig -c++ -cgo -go -intgosize 64  example.i 生成golang调用的包装代码:example.go和example_wrap.cxx;example_wrap.cxx文件将c++语法隐藏在C函数内部,对外暴露c接口,example.go调用example_wrap.cxx中的c函数,声明并实现golang版的接口。

runme.go中引入example包  . "./example"

c := NewCircle(10) 简短变量声明并定义了SwigcptrCircle类型的变量,SwigcptrCircle实现了Circle 接口。SwigcptrCircle的基础类型是uintptr,NewCircle返回的值实际上就是C++对象的this指针,通过SwigcptrCircle类型的值调用Circle 接口定义的方法,实质上是通过example_wrap.cxx暴露的C函数及“this指针”在函数内部调用将指针转换成c++对象指针然后调用相应的方法。

type Circle interface {

Swigcptr() uintptr

SwigIsCircle()

Area() (_swig_ret float64)

Perimeter() (_swig_ret float64)

SetX(arg1 float64)

GetX() (_swig_ret float64)

SetY(arg1 float64)

GetY() (_swig_ret float64)

Move(arg1 float64, arg2 float64)

SwigIsShape()

SwigGetShape() Shape

}

从Golang的角度看,借助swig生成的包装类型,调用c++类方法就像调用golang内部的接口一样,非常简单易用。

在实际的项目开发中,包含了大量的C++头文件和源码文件,通常还会引入大量的第三方库文件。我们的项目中,开发人员编写的代码超过五十万行,还有大量的第三方库,例如boost、thrift、redis等,所有C++代码量超过几百万行,编译后的输出包含大量的动态链接库及少量的可执行程序;在服务端,进行跨语言混合开发无外乎涉及两方面,实现库时提供不同语言的实现,例如使用thrift框架可以生成C++、Java、Golang等语言的客户端、服务端版本,不同的组件可实现跨语言跨平台调用;另外一种主要涉及跨语言库调用。Examples\go目录下的示例没有讲述如何实现golang调用C++ dll,并且在官方文档中也没有找到如何实现。(通过D:\swigwin-3.0.12\Doc\Manual\index.html 可以查看最新版的3.0文档)。Google加百度没有找到一篇文档能够详细地指出windows环境下golang调用c++ dll的方法,在不断地编码尝试下,最终自己搞定。具体细节在后两篇文档中指出。

calling c++ from golang with swig--windows dll(一)的更多相关文章

  1. calling c++ from golang with swig--windows dll (三)

    calling c++ from golang with swig--windows dll 三 使用动态链接库(DLL)主要有两种方式:一种通过链接导入库,在代码中直接调用DLL中的函数:另一种借助 ...

  2. calling c++ from golang with swig--windows dll (四)

    calling c++ from golang with swig--windows dll 四 前面讲述了windows环境下golang如何通过swig调用C++ dll.由于编译c++代码使用了 ...

  3. calling c++ from golang with swig--windows dll 二

    Name mangling && Name demangling 在讲述golang如何利用swig调用windows dll之前,需要了解一个概念:Name Mangling (或者 ...

  4. golang调用c++的dll库文件

    最近使用golang调用c++的dll库文件,简单了解了一下,特作此笔记:一.DLL 的编制与具体的编程语言及编译器无关 dll分com的dll和动态dll,Com组件dll:不管是何种语言写的都可以 ...

  5. Windows Dll Injection、Process Injection、API Hook、DLL后门/恶意程序入侵技术

    catalogue 1. 引言2. 使用注册表注入DLL3. 使用Windows挂钩来注入DLL4. 使用远程线程来注入DLL5. 使用木马DLL来注入DLL6. 把DLL作为调试器来注入7. 使用c ...

  6. go 调用windows dll 的方法

    go 调用windows dll 的方法 ,代码如下: package main import ( "fmt" "syscall" "time&quo ...

  7. C#实现动态调用Windows DLL

    调用方法: object obj = WinDllInvoke("Kernel32.dll", "Beep", , }, typeof(void)); 函数代码 ...

  8. Creating Icon Overlay Handlers / 创建图标标记 Handlers (翻译自MSDN) / VC++, Windows, DLL, ATL, COM

    创建图标标记 Handlers Creating Icon Overlay Handlers 图标标记是放在代表着某个 Shell 对象的图标之左下角的小图像.它们通常被加在一个对象的图标的身上来提供 ...

  9. Windows DLL资料整理

    1.使用Visual C++ 6.0创建dll 2. 函数的调用规则(__cdecl,__stdcall,__fastcall,__pascal) 要点: 1. 如果你的程序中没有涉及可变参数,最好使 ...

随机推荐

  1. Crystal框架配置参数加载机制详解?

    前言 定义 配置参数定义的形式 配置参数文件定义在哪里? 配置参数加载的优先级 如何使用配置参数? 最佳实践 Jar项目中如何定义配置参数? War项目中如何定义或重载Jar包中的配置参数? 开发人员 ...

  2. 转载:MAT Memory Analyzer Tool使用示例

    地址:http://blog.csdn.net/yanghongchang_/article/details/7711911 以下是一个会导致java.lang.OutOfMemoryError: J ...

  3. MyBatis中多对多关系的映射和查询

    先说一下需求: 在页面上显示数据库中的所有图书,显示图书的同时,显示出该图书所属的类别(这里一本书可能同时属于多个类别) 创建表: 笔者这里使用 中间表 连接 图书表 和 图书类别表,图书表中 没有使 ...

  4. 【java设计模式】之 抽象工厂(Abstract Factory)模式

    1. 女娲的失误 上一节学习了工厂模式,女娲运用了该模式成功创建了三个人种,可是问题来了,她发现没有性别--这失误也忒大了点吧--竟然没有性别,那岂不是--无奈,只好抹掉重来了,于是所有人都被消灭掉了 ...

  5. [JQuery]Jquery对象和dom对象

    jquery对象是jquery包装dom对象后产生的对象,它们都只能使用各自的方法. 1.定义变量时,通过$来区分: var $variable = jquery对象: var variable = ...

  6. Wireshark网络抓包(三)——网络协议

    一.ARP协议 ARP(Address Resolution Protocol)地址解析协议,将IP地址解析成MAC地址. IP地址在OSI模型第三层,MAC地址在OSI第二层,彼此不直接通信: 在通 ...

  7. 法国总统放大招,用“分身术”竞选总统 全息3d 网

    编辑:大熊 [摘要]法国总统采用全息技术实现"分身"演讲,可谓是一次演讲,全面覆盖! 全息3d网讯:众所周知,欧美国家的总统是通过公开竞选得到的,所以能更直接.更广泛的近距离接触民 ...

  8. 很傻很二很简单的一个问题,json键值为变量如何取值

    js里的json的键值是变量的话,那么传统的做法似乎不管用了. 例如: var json={'a':'123','b':'999'}    json.a得到123,如果a用变量表示呢,有笨法for循环 ...

  9. 重新学习WCF

    近来工作不怎么忙,一直在想一个问题,今年刚刚毕业,对于我们这应届生到底应该学习那些技术呢? 面对着现在技术横生,到底哪项是适合自己的呢?自己一直都在迷茫,若有那位大神再次经过,望给出您宝贵的建议. 最 ...

  10. Kafka概念入门(一)

    序:如何保证kafka全局消息有序? 比如,有100条有序数据,生产者发送到kafka集群,kafka的分片有4个,可能的情况就是一个分片保存0-25,一个保存25-50......这样消息在kafk ...