首页 > 编程语言 >Calling C++ Code From Go With SWIG

Calling C++ Code From Go With SWIG

时间:2023-02-13 14:13:04浏览次数:53  
标签:std Code SWIG C++ go Go simplelib

http://zacg.github.io/blog/2013/06/06/calling-c-plus-plus-code-from-go-with-swig/

 

Recently while working on a Go based project I needed to use some functionality from another large C++ library. The library’s size and complexity made re-writing it in Go unfeasible. After some research I decided to use the popular SWIG (Simplified Wrapper and Interface Generator) framework to enable interop between my two projects.

The following is a brief tutorial to guide you through wrapping a C++ class with a Go package which can be called from any Go program.

Start by installing GO and SWIG if not already installed

1
2
sudo apt-get install golang
sudo apt-get install swig

Update: The debian package is out of date and lacking many go related fixes, it is best to install current SWIG release from SWIG website: http://swig.org

I also recommend installing golang from source as some of the following commands only work with go 1.1 and up. http://golang.org/doc/install/source

Once everything in installed the first step is to define a module file which will tell the SWIG tool what code in the C++ project to expose in the resulting GO package. We’ll assume your project is object oriented with cpp/header files for each class, when this is the case we can just include the desired header files in our SWIG module.

 

We will pretend our C++ project is a dynamically linked shared library called “simplelib” and contains the following files:

 

 

1
2
3
simpleclass.h
simpleclass.cpp


 

 

simpleclass.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef SIMPLECLASS_H
#define SIMPLECLASS_H

#include <iostream>
#include <vector>

class SimpleClass
{
public:
    SimpleClass(){};
    std::string hello();
    void helloString(std::vector<std::string> results);
    void helloBytes(std::vector<char> results);
};

#endif



 

 

simpleclass.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "simpleclass.h"

std::string SimpleClass::hello(){
  return "world";
}

void SimpleClass::helloString(std::vector<std::string> results){
  results->push_back("world");
}

void SimpleClass::helloBytes(std::vector<char> results){
  results->push_back('w');
  results->push_back('o');
  results->push_back('r');
  results->push_back('l');
  results->push_back('d');
}



 

 

We will add a module file called simplelib.swig. Inside we include the simpleclass.h header, this will instruct the SWIG tool to generate wrapping code for this class allowing us to use it in GO.

 

 

Minimum Swig Template
1
2
3
%module simplelib  //name of the resulting GO package

%include "simpleclass.h"

 

 

If your wrapped class(es) are simple and use primitive types the above swig file should suffice, SWIG will translate the following primitive types to the specified Go types

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

C/C++ type Go type
bool bool
char byte
signed char int8
unsigned char byte
short int16
unsigned short uint16
int int
unsigned int uint
long int32 or int64, depending on -long-type-size
unsigned long uint32 or uint64, depending on -long-type-size
long long int64
unsigned long long uint64
float float32
double float64
char *
char []
string

 

 

 

If your target code contains non-primitive types you have a bit more work to do. SWIG includes headers to help with common non primitive types like string and vector from the standard library. Vectors bring up another issue because they use templates, template types have to be explicitly defined in your SWIG mapping file. A class that uses std::string and std::vector might look like the following:

 

 

simplelib.swig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
%module simplelib

%include <typemaps.i>
%include "std_string.i"
%include "std_vector.i"

// This will create 2 wrapped types in Go called
// "StringVector" and "ByteVector" for their respective
// types.
namespace std {
   %template(StringVector) vector<string>;
   %template(ByteVector) vector<char>;
}

%include "simpleclass.h"

 



 

The following definitions are included with the SWIG library, go here for full reference

 

 

 

 

 

 

C++ class C++ Library file SWIG Interface library file
std::deque deque std_deque.i
std::list list std_list.i
std::map map std_map.i
std::pair utility std_pair.i
std::set set std_set.i
std::string string std_string.i
std::vector vector std_vector.i

 



 

Next we need to generate the necessary C++ wrapper code to allow Go to bind to it.

 

 

Update: With the official release of Go 1.2, the go build tool now recognizes SWIG files. The following steps are not necessary but may still be useful for users with more complicated build systems.

If you are using Go 1.2 simply include the .swig module file in your package directory along with the relevant c++ code files and run “go build” or “go install”

 

 

1
2
3
cd /project/src/
SWIG -go -c++ simplelib.swig


 

 

Common optional parameters you may need to use:

  • “-soname” for specifying the name of your compiled shared library which is dynamically linked at runtime. e.g. -soname libSimpleLib.so.1
  • “-intgosize” Depending on which version of go you are using 1/1.1 and which platform you are targeting you may need to explicitly set the Go int size (note the documentation for this is currently out of date). e.g. -intgosize 64

 

 

 

The above SWIG command should generate 3 new files in your project directory. Your project directory should now look something like the following:

 

 

1
2
3
4
5
6
simpleclass.h
simpleclass.cpp
simplelib.swig
simplelib.go
simplelib.cxx
simplelib_gc.c

 

 

Now we need to include these 3 new files in our projects. Simplelib.cxx contains the C++ wrapper code allowing your C++ project to interop with CGO. simplelib_gc.c contains the C code designed to be called from CGO. simplelib.go contains the GO code stubs for the resulting GO package, it uses cgo to call into the simplelib_gc.c interfaces.

Add the simplelib.cxx file to the C++ project and build with the projects C++ compiler (I have only tested this process with GCC). Simply add it to your makefile or build script.

 

 

simplelib_gc.c and simplelib.go need to be included in the go package using the following 5/6/8c and 5/6/8g commands.

 

 

1
2
3
go tool 6c -I <Go Installation Path here>/pkg/linux_amd64/ -D _64BIT simplelib_gc.c
go tool 6g simplelib.go
go tool pack grc simplelib.a simplelib.6 simplelib_gc.6

 

 

The last step is installation: first install your compiled C++ shared library, then run go install on the package created in the last step.

 

 

1
2
cd /go/src/simplelib/
go install

 

 

If the installation was successful you should see simplelib.a file in /go/pkg//

 

 

That’s it! you should now be able to import “simplelib” in your go projects and call the wrapped C++ code.

 

 

Setting up Build Scripts

 

 

To recap the steps required are:

 

 

  1. Run SWIG tool (generate wrapper code)
  2. Compile C++ project (including new wrapper code)
  3. Copy the built C++ library and files generated in step 1 to a directory in your go path
  4. Link and package the generated files into a Go Package
  5. Run Go install to make the new package available in your applications

 

 

And here is an example makefile:

 

 

simplelib.make
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
CC=g++

ifeq ($(DEBUG),yes)
  CXXFLAGS=-Wall -g
  LDFLAGS=-Wall -g
else
  CXXFLAGS=-Wall
  LDFLAGS=-Wall
endif

INCPATH=inc
SRCPATH=src
OBJPATH=obj
LIBPATH=lib
BINPATH=bin

OBJS=$(OBJPATH)/simpleclass.o $(OBJPATH)/simplelib_wrap.o
OUT=$(LIBPATH)/libSimpleLib.so

INCLUDES=-I ./$(INCPATH)

#Set this to your go installation directory
EXE=$$HOME/dev/goinstallation/go/bin/
export PATH := bin:$(PATH)

default: $(OUT)

$(OUT): $(OBJS)
  $(CC) $(LDFLAGS) -shared -o $@ $^

obj/simplelib_wrap.o: simplelib_wrap.cxx inc/simpleclass.h
  $(CC) $(CXXFLAGS) $(INCLUDES) -fpic -c $< -o $@

obj/simpleclass.o: src/simpleclass.cpp inc/simpleclass.h
  $(CC) $(CXXFLAGS) $(INCLUDES) -fpic -c $< -o $@


simplelib_wrap.cxx:
  swig -go -c++ -intgosize 64 -soname libSimpleLib.so simplelib.swig

.PHONY: clean cleanall

clean:
  rm -f $(OBJPATH)/.o

cleanall: clean
  rm -f $(OUT)
  rm -f .6
  rm -f .a
  rm -f .so
  rm -f .cxx
  rm -f .c

build:
  @echo "Building bindings..."
  $(EXE)go tool 6c -I $$HOME/dev/goinstallation/go/pkg/linux_amd64/ -D _64BIT simplelib_gc.c
  $(EXE)go tool 6g simplelib.go
  $(EXE)go tool pack grc simplelib.a simplelib.6 simplelib_gc.6




install:
  @echo "Installing go package..."
  #Rename swig file so go install command does not try to reprocess it
  mv simplelib.swig simplelib.notswig
  export GOPATH=$$HOME/dev/go/; </span>
  $(EXE)go install
  mv simplelib.notswig simplelib.swig

  @echo "Installing go shared lib..."
  sudo cp -f lib/libSimpleLib.so /usr/local/lib/
  sudo ldconfig

 

 

 

Get example project on github: https://github.com/zacg/simplelib

 

 

 

 

Feel free to leave your comments below.

 

标签:std,Code,SWIG,C++,go,Go,simplelib
From: https://www.cnblogs.com/jiftle/p/17116118.html

相关文章

  • Codeforces Round #852 (Div. 2)
    F.Rebrending题目抽象为现有长度为\(n\)的数组\(a_1,a_2,\cdots,a_n\),\(m\)次询问,每次询问\(\min\limits_{l\lei,j\ler,i\neqj}|a_i-a_j|\)\((1\lel<r\len)......
  • Vscode报错: error:0308010C:digital envelope routines::unsupported错误记录解决
    Vscode报错:error:0308010C:digitalenveloperoutines::unsupported错误记录解决因为安装了新版本的node才报的错误:node版本:v18.14.0运行npmrunserve报错解决办法:......
  • #0033. Educational Codeforces Round 3
    609A贪心优先选大的USBflashdrive609B先处理每个genre的书有多少本,然后直接枚举每次购买的是哪两种genre然后乘法原理即刻609C手下考虑balanced的长啥样。假设这n......
  • VScode 配置C++环境记录
    gcc/g++是c/c++编译器,Windows需要借助Mingw来使用c++的编译器,下面是安装MinGW的教程:搬运:https://blog.csdn.net/jjxcsdn/article/details/123058745在VScode中配置编译......
  • #0032. Educational Codeforces Round 2
    600A简单题但有个坑点在于会有空字符串600B一道可以用来实验upper_bound的题600C挺有趣的一道题。首先考虑怎样的字符串可以通过permutation变成palindrome:条件是至......
  • 【问题讨论】关于golang调用so的问题的讨论
    runtime:dlopen/dlsymwithoutCGo#18296 Open  iamacarpetopenedthisissueDec13,2016·12comments  Open  ......
  • leetcode 1233. 删除子文件夹
    ​​1233.删除子文件夹​​难度中等142你是一位系统管理员,手里有一份文件夹列表 ​​folder​​,你的任务是要删除该列表中的所有 子文件夹,并以 任意顺序 返回剩下的......
  • go连接kafka
    Part1前言本文主要介绍如何通过go语言连接kafka。这里采用的是sarama库。​​https://github.com/Shopify/sarama​​Part2库的安装goget-ugithub.com/Shopify/saramago......
  • VS与VS Code的EF Core常用命令(Code First)
    概述:在VSCode中错误使用了EFCore命令,特此记录下。  常用终端命令: VSVSCode新增/修改Add-Migration迁移名称dotnetefmigrationsadd迁移名称......
  • golang 切片 slice
    1.基本介绍切片是数组的一个引用,因此切片是引用类型。切片的使用与数组类似,遍历,访问切片元素等都一样。切片是长度是可以变化的,因此切片可以看做是一个动态数组。slice内......